RDK Documentation (Open Sourced RDK Components)
mediaplayerdlna.cpp
1 /*
2  * If not stated otherwise in this file or this component's Licenses.txt 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 #include "mediaplayerdlna.h"
20 
21 #include <algorithm>
22 #include <sstream>
23 #include <string>
24 #include <vector>
25 #include <limits>
26 #include <cmath>
27 #include <cassert>
28 #include <cstring>
29 
30 #include <gst/audio/streamvolume.h>
31 #include <gst/video/video.h>
32 #include <curl/curl.h>
33 
34 #include <hnsource.h>
35 #include <mediaplayersink.h>
36 #include <dumpfilesink.h>
37 
38 #ifdef ENABLE_DIRECT_QAM
39 #include <rmfqamsrc.h>
40 #ifdef USE_VODSRC
41 #include <rmfvodsource.h>
42 #endif
43 #ifdef IPPV_CLIENT_ENABLED
44 #include <ippvsrc.h>
45 #endif
46 #endif
47 #include <rmfqamsrcpriv.h>
48 #include "rmfprivate.h"
49 
50 #include "logger.h"
51 
52 #define HEADER_NAME_SEEK_RANGE "availableSeekRange.dlna.org"
53 #define HEADER_NAME_PLAYSPEED "PlaySpeed.dlna.org"
54 #define HEADER_NAME_VODADINSERTION_STATUS "vodAdInsertionStatus.cmst.com"
55 #define RMF_VOD_BEGIN_PLAYBACK 7
56 #define RMF_VOD_BAD_START_POSITION_VAL 0x7FFFFFFFu
57 
58 #define CURL_EASY_SETOPT(curl, CURLoption ,option) \
59  if (curl_easy_setopt(curl, CURLoption ,option) != 0) {\
60  LOG_ERROR("Failed at curl_easy_setopt %d \n", curl); \
61  } //CID:127965 - checked return
62 typedef std::vector<std::string> headers_t;
63 
64 struct RequestInfo {
65  std::string url;
66  headers_t headers;
67 };
68 
69 struct ResponseInfo {
70  int http_code;
71  std::string url;
72  std::string payload;
73  headers_t headers;
74 };
75 
76 namespace {
77 
78 bool starts_with(const std::string &s, const std::string &starting) {
79  if (starting.size() > s.size())
80  return false;
81  return std::equal(starting.begin(), starting.end(), s.begin());
82 }
83 
84 bool ends_with(const std::string &s, const std::string &ending) {
85  if (ending.size() > s.size())
86  return false;
87  return std::equal(ending.rbegin(), ending.rend(), s.rbegin());
88 }
89 
90 bool has_substring(const std::string &s, const std::string &substring) {
91  return s.find(substring) != std::string::npos;
92 }
93 
94 std::vector<std::string>& split_string(
95  const std::string &s, char delim, std::vector<std::string> &elems) {
96  std::stringstream ss(s);
97  std::string item;
98  while (std::getline(ss, item, delim)) {
99  elems.push_back(item);
100  }
101  return elems;
102 }
103 
104 std::string &ltrim_string(std::string &s) {
105  s.erase(
106  s.begin(),
107  std::find_if(
108  s.begin(),
109  s.end(),
110  std::not1(std::ptr_fun<int, int>(std::isspace))));
111  return s;
112 }
113 
114 std::string &rtrim_string(std::string &s) {
115  s.erase(
116  std::find_if(
117  s.rbegin(),
118  s.rend(),
119  std::not1(std::ptr_fun<int, int>(std::isspace))).base(),
120  s.end());
121  return s;
122 }
123 
124 std::string &trim_string(std::string &s) {
125  return ltrim_string(rtrim_string(s));
126 }
127 
128 std::string& find_header(const headers_t &headers, const std::string &header_name, std::string &header_value) {
129  header_value = std::string();
130  for (headers_t::const_iterator cit = headers.begin();
131  cit != headers.end(); ++cit) {
132  const std::string& raw_header = *cit;
133  if (starts_with(raw_header, header_name)) {
134  const size_t column_pos = raw_header.find_first_of(':');
135  header_value = raw_header.substr(column_pos + 1);
136  header_value = trim_string(header_value);
137  break;
138  }
139  }
140  return header_value;
141 }
142 
143 const int kCurlTimeoutInSeconds = 30;
144 
145 #if LIBCURL_VERSION_NUM >= 0x071306
146 #define _CURLINFO_RESPONSE_CODE CURLINFO_RESPONSE_CODE
147 #else
148 #define _CURLINFO_RESPONSE_CODE CURLINFO_HTTP_CODE
149 #endif
150 
151 size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp) {
152  size_t realsize = size * nmemb;
153  std::string *mem = reinterpret_cast<std::string*>(userp);
154  *mem += std::string(reinterpret_cast<char*>(contents), realsize);
155  return realsize;
156 }
157 
158 class MediaEvents : public IRMFMediaEvents {
159  public:
160  explicit MediaEvents(MediaPlayerDLNA* player) : m_player(player) {}
161  void playing() { m_player->onPlay(); }
162  void paused() { m_player->onPause(); }
163  void stopped() { m_player->onStop(); }
164  void complete() {
165  LOG_INFO("DLNA player: End of Stream");
166  m_player->ended();
167  }
168  void error(RMFResult err, const char* msg) {
169  LOG_ERROR("DLNA player: Error %s (%d)", msg, (int)err);
170  m_player->notifyError(err, msg);
171  }
172  void status(const RMFStreamingStatus& status) {
173  LOG_ERROR("DLNA player: Status %d", status.m_status);
174  m_player->notifyStatus(status);
175  }
176  void section(const void* data_ptr, unsigned int data_size){
177  LOG_ERROR("DLNA player: Section Data Received");
178  //m_player->notifyStatus(status);
179  }
180  private:
181  MediaPlayerDLNA* m_player;
182 };
183 
184 MediaPlayerDLNA *g_playerInstance = NULL;
185 
186 } // namespace
187 
188 static void mediaPlayerPrivateHaveVideoCallback(void* player) {
189  LOG_INFO("Got video");
190  ASSERT(player == g_playerInstance);
191  static_cast<MediaPlayerDLNA*>(player)->notifyPresenceOfVideo();
192 }
193 
194 static void mediaPlayerPrivateHaveAudioCallback(void* player) {
195  LOG_INFO("Got audio");
196 }
197 
198 static void mediaPlayerPrivateEISSDataCallback(void* player)
199 {
200  //LOG_INFO("Got EISS");
201  ASSERT(player == g_playerInstance);
202  static_cast<MediaPlayerDLNA*>(player)->notifyPlayerOfEISSData();
203 }
204 static void mediaPlayerPrivateAudioNotifyFirstFrameCallback(void* player) {
205  ASSERT(player == g_playerInstance);
206  static_cast<MediaPlayerDLNA*>(player)->notifyPlayerOfFirstAudioFrame();
207 }
208 
209 static void mediaPlayerPrivateNotifyMediaWarningCallback(void* player) {
210  ASSERT(player == g_playerInstance);
211  static_cast<MediaPlayerDLNA*>(player)->notifyPlayerOfMediaWarning();
212 }
213 
214 static void mediaPlayerPrivateVideoNotifyFirstFrameCallback(void* player) {
215  ASSERT(player == g_playerInstance);
216  static_cast<MediaPlayerDLNA*>(player)->notifyPlayerOfFirstVideoFrame();
217 }
218 
219 static void mediaPlayerPrivateNotifyPmtUpdateCallback(void* player) {
220  LOG_INFO("Got AV Pids");
221  ASSERT(player == g_playerInstance);
222  static_cast<MediaPlayerDLNA*>(player)->notifyPMTUpdate();
223 }
224 
225 static void mediaPlayerLanguageChangeCallback(void* player) {
226  LOG_INFO("Got LanguageChange");
227  ASSERT(player == g_playerInstance);
228  static_cast<MediaPlayerDLNA*>(player)->notifyLanguageChange();
229 }
230 
231 bool MediaPlayerDLNA::isVOD() const {
232  return has_substring(m_url, "vod://");
233 }
234 
235 bool MediaPlayerDLNA::isOCAP() const {
236  return has_substring(m_url, "ocap://");
237 }
238 
239 bool MediaPlayerDLNA::isMpegTS() const {
240  return ends_with(m_url, ".ts") || has_substring(m_url, "/vldms/") ||
241  has_substring(m_url, "profile=MPEG_TS");
242 }
243 
244 MediaPlayerDLNA::MediaPlayerDLNA(MediaPlayerClient* client)
245  : m_playerClient(client)
246  , m_hnsource(0)
247  , m_source(0)
248  , m_sink(0)
249  , m_dfsink(0)
250  , m_events(new ::MediaEvents(this))
251  , m_events_sink(new ::MediaEvents(this))
252  , m_changingRate(false)
253  , m_endTime(std::numeric_limits<float>::infinity())
254  , m_playerState(MediaPlayer::RMF_PLAYER_EMPTY)
255  , m_videoState(MediaPlayer::RMF_VIDEO_BUFFER_HAVENOTHING)
256  , m_isStreaming(false)
257  , m_paused(true)
258  , m_pausedInternal(true)
259  , m_seeking(false)
260  , m_playbackRate(1)
261  , m_errorOccured(false)
262  , m_mediaDuration(0)
263  , m_delayingLoad(false)
264  , m_mediaDurationKnown(false)
265  , m_volumeTimerHandler(0)
266  , m_muteTimerHandler(0)
267  , m_muted(false)
268  , m_lastKnownRect()
269  , m_currentPosition(0)
270  , m_isVOnlyOnce(true)
271  , m_isAOnlyOnce(true)
272  , m_isEndReached(false)
273  , m_isInProgressRecording(false)
274  , m_errorMsg("")
275  , m_progressTimer(this, &MediaPlayerDLNA::onProgressTimerTimeout)
276  , m_baseSeekTime(0.0)
277  , m_currentProgressTime(0.0)
278  , m_rmfMediaWarnDesc("")
279  , m_rmfAudioTracks("")
280  , m_rmfCaptionDescriptor("")
281  , m_rmfEISSDataBuffer("")
282  , m_rmfMediaWarnData(0)
283  , m_networkBufferSize(0)
284  , m_restartPlaybackCount(0)
285  , m_allowPositionQueries(false)
286  , m_EOSPending(false)
287  , m_fetchTrickModeHeaders(false)
288  , m_isVODPauseRequested(false)
289  , m_isVODRateChangeRequested(false)
290  , m_isVODSeekRequested(false)
291  , m_isVODAsset(false)
292  , m_isMusicOnlyAsset(true) /* It will be reset when Video Frame is found */
293 #ifdef ENABLE_DIRECT_QAM
294  , m_isLiveAsset(false)
295  , m_isPPVAsset(false)
296  , m_isDVRAsset (false)
297 #endif
298  , m_VODKeepPipelinePlaying(true)
299  , m_eissFilterStatus(false)
300  , m_onFirstVideoFrameHandler(0)
301  , m_onFirstAudioFrameHandler(0)
302  , m_onEISSDUpdateHandler(0)
303  , m_psiStatus(0)
304  , m_pmtUpdate(false)
305  , m_audioMuteStatus(false)
306  , m_onMediaWarningReceivedHandler(0) {
307  LOG_INFO("DLNA video player created");
308  g_playerInstance = this;
309 
310  char *pVODKeepPipelinePlaying = NULL;
311  pVODKeepPipelinePlaying = getenv("RMF_VOD_KEEP_PIPELINE");
312  errno_t safec_rc = -1;
313  int ind = -1;
314 
315  if (pVODKeepPipelinePlaying ) {
316  safec_rc = strcasecmp_s("FALSE", strlen("FALSE"), pVODKeepPipelinePlaying, &ind);
317  ERR_CHK(safec_rc);
318  if((safec_rc == EOK) && (ind == 0)) {
319  m_VODKeepPipelinePlaying = false;
320  }
321  }
322  m_maxTimeLoaded = 0.0f; //CID 87555 - Initialized values
323  m_videoTimerHandler = 0;
324  m_audioTimerHandler = 0;
325  m_startedBuffering = false;
326  m_isVOD5XHackEnabled = true;
327 }
328 
329 MediaPlayerDLNA::~MediaPlayerDLNA() {
330  LOG_INFO("DLNA video player destroying");
331 
332  if (this == g_playerInstance)
333  g_playerInstance = NULL;
334 
335  if (m_progressTimer.isActive())
336  m_progressTimer.stop();
337 
338  rmf_stop();
339 
340  m_playerClient = NULL;
341 
342  delete m_events;
343  m_events = NULL;
344 
345  delete m_events_sink;
346  m_events_sink = NULL;
347 
348  if (m_muteTimerHandler)
349  g_source_remove(m_muteTimerHandler);
350 
351  if (m_volumeTimerHandler)
352  g_source_remove(m_volumeTimerHandler);
353 
354  if (m_onFirstVideoFrameHandler)
355  g_source_remove(m_onFirstVideoFrameHandler);
356 
357  if (m_onFirstAudioFrameHandler)
358  g_source_remove(m_onFirstAudioFrameHandler);
359 
360  if (m_onMediaWarningReceivedHandler)
361  g_source_remove(m_onMediaWarningReceivedHandler);
362 
363  if (m_onEISSDUpdateHandler)
364  g_source_remove(m_onEISSDUpdateHandler);
365 
366  ASSERT(!m_sink);
367  ASSERT(!m_dfsink);
368  ASSERT(!m_source);
369 
370  LOG_INFO("DLNA video player destroyed");
371 }
372 
373 void MediaPlayerDLNA::notifyError(RMFResult err, const char *pMsg) {
374  std::string tmp = "130:ErrorCode:Unknown Error";
375  if (pMsg)
376  tmp = std::string(pMsg);
377 
378  /* Set the Error msg first before posting the error */
379 #ifdef ENABLE_DIRECT_QAM
380  getErrorMapping(err, pMsg);
381 #else
382  setMediaErrorMessage(tmp);
383 #endif /* ENABLE_DIRECT_QAM */
384  loadingFailed(MediaPlayer::RMF_PLAYER_DECODEERROR);
385 }
386 
387 void MediaPlayerDLNA::notifyStatus(const RMFStreamingStatus& status) {
388  LOG_INFO("notifyStatus - Status %d", status.m_status);
389  bool psiEvent = false;
390  switch (status.m_status)
391  {
392  case RMF_QAMSRC_EVENT_PAT_ACQUIRED:
393  LOG_INFO("notifyStatus - Status - RMF_QAMSRC_EVENT_PAT_ACQUIRED");
394  m_psiStatus |= PAT_ACQUIRE;
395  psiEvent = true;
396  break;
397  case RMF_QAMSRC_EVENT_PMT_ACQUIRED:
398  LOG_INFO("notifyStatus - Status - RMF_QAMSRC_EVENT_PMT_ACQUIRED");
399  m_psiStatus |= PMT_ACQUIRE;
400  psiEvent = true;
401  break;
402  case RMF_QAMSRC_EVENT_CAT_ACQUIRED:
403  LOG_INFO("notifyStatus - Status - RMF_QAMSRC_EVENT_CAT_ACQUIRED");
404  m_playerClient->psiUpdateReceived(CAT_ACQUIRE);
405  m_psiStatus |= CAT_ACQUIRE;
406  psiEvent = true;
407  break;
408  case RMF_QAMSRC_EVENT_PAT_UPDATE:
409  LOG_INFO("notifyStatus - Status - RMF_QAMSRC_EVENT_PAT_UPDATE");
410  m_playerClient->psiUpdateReceived(PAT_UPDATE);
411  break;
412  case RMF_QAMSRC_EVENT_CAT_UPDATE:
413  LOG_INFO("notifyStatus - Status - RMF_QAMSRC_EVENT_CAT_UPDATE");
414  m_playerClient->psiUpdateReceived(CAT_UPDATE);
415  break;
416  case RMF_QAMSRC_EVENT_PMT_UPDATE:
417  LOG_INFO("notifyStatus - Status - RMF_QAMSRC_EVENT_PMT_UPDATE");
418  m_playerClient->psiUpdateReceived(PMT_UPDATE);
419  m_pmtUpdate = true;
420  onPMTUpdateAudioMute();
421  break;
422  }
423  if(status.m_status == RMF_QAMSRC_EVENT_SECTION_ACQUIRED) {
424  LOG_INFO("Section Data is avialable to read");
425  m_playerClient->sectionDataReceived();
426  }
427  else if(psiEvent && (m_psiStatus == PSI_READY)){
428  LOG_INFO("PSI Data (PAT, PMT and CAT) is ready");
429  //m_playerClient->psiReady();
430  }
431 }
432 
433 uint32_t MediaPlayerDLNA::getPATBuffer(std::vector<uint8_t>& buf) {
434  uint32_t length = 0;
435  //m_source->getPrivateSourceImpl()->getPATBuffer(buf, length);
436  ((RMFQAMSrcImpl *)(m_source->getPrivateSourceImpl()))->getPATBuffer(buf, &length);
437  return length;
438 }
439 
440 uint32_t MediaPlayerDLNA::getPMTBuffer(std::vector<uint8_t>& buf) {
441  uint32_t length = 0;
442  m_source->getPrivateSourceImpl()->getPMTBuffer(buf, &length);
443  return length;
444 }
445 
446 uint32_t MediaPlayerDLNA::getCATBuffer(std::vector<uint8_t>& buf) {
447  uint32_t length = 0;
448  m_source->getPrivateSourceImpl()->getCATBuffer(buf, &length);
449  return length;
450 }
451 
452 bool MediaPlayerDLNA::getAudioPidFromPMT(uint32_t *pid, const std::string& audioLang) {
453  return m_source->getPrivateSourceImpl()->getAudioPidFromPMT(pid, audioLang);
454 }
455 
456 void MediaPlayerDLNA::onPMTUpdateAudioMute()
457 {
458  uint32_t pid;
459  // CAUTION! Uses short-circuit evaluation
460  if(
461  (!getAudioPidFromPMT(&pid, m_sink->getAudioTrackSelected())) &&
462  (!getAudioPidFromPMT(&pid, m_sink->getPreferredAudioLanguage())) &&
463  (!getAudioPidFromPMT(&pid, ""))
464  ){
465  LOG_ERROR("Failed to get AudioPid from PMT");
466  return;
467  }
468  LOG_INFO("onPMTUpdateAudioMute updated audioPid - %p\n", pid);
469  if(pid != m_playerClient->getCurrentAudioPid())
470  {
471  LOG_INFO("Setting AudioMute");
472  rmf_setAudioMute(true);
473  }
474 }
475 bool MediaPlayerDLNA::getAudioMute() const
476 {
477  return m_audioMuteStatus;
478 }
479 
480 
481 uint32_t MediaPlayerDLNA::getSectionData(uint32_t *filterId, std::vector<uint8_t>& sectionData)
482 {
483  uint32_t length = 0;
484  m_source->getPrivateSourceImpl()->getSectionData(filterId, sectionData, &length);
485  return length;
486 }
487 
488 void MediaPlayerDLNA::setFilter(uint16_t pid, char* filterParam, uint32_t *pFilterId)
489 {
490  LOG_INFO("MediaPlayerDLNA::setFilter");
491  m_source->getPrivateSourceImpl()->setFilter(pid, filterParam, pFilterId);
492 }
493 
494 void MediaPlayerDLNA::releaseFilter(uint32_t filterId)
495 {
496  LOG_INFO("MediaPlayerDLNA::releaseFilter");
497  m_source->getPrivateSourceImpl()->releaseFilter(filterId);
498 }
499 
500 void MediaPlayerDLNA::resumeFilter(uint32_t filterId)
501 {
502  LOG_INFO("MediaPlayerDLNA::resumeFilter");
503  m_source->getPrivateSourceImpl()->resumeFilter(filterId);
504 }
505 
506 void MediaPlayerDLNA::pauseFilter(uint32_t filterId)
507 {
508  LOG_INFO("MediaPlayerDLNA::pauseFilter");
509  m_source->getPrivateSourceImpl()->pauseFilter(filterId);
510 }
511 
512 #ifdef ENABLE_DIRECT_QAM
513 void MediaPlayerDLNA::getErrorMapping(RMFResult err, const char *pMsg)
514 {
515  std::string errorMsg = "Unknown Error";
516  std::string inputErr = "Unknown Error";
517  if (pMsg)
518  inputErr = std::string(pMsg);
519 
520  if (m_isVODAsset)
521  errorMsg = "130:Error:" + inputErr;
522  else if (m_isLiveAsset | m_isPPVAsset)
523  {
524  std::string errorCode = "0";
525  switch (err)
526  {
527  case RMF_QAMSRC_EVENT_CANNOT_DESCRAMBLE_ENTITLEMENT:
528  case RMF_QAMSRC_EVENT_CANNOT_DESCRAMBLE_RESOURCES:
529  case RMF_QAMSRC_EVENT_MMI_PURCHASE_DIALOG:
530  case RMF_QAMSRC_EVENT_MMI_TECHNICAL_DIALOG:
531  case RMF_QAMSRC_EVENT_POD_REMOVED:
532  case RMF_QAMSRC_EVENT_POD_RESOURCE_LOST:
533  errorCode = "101";
534  break;
535 
536  case RMF_QAMSRC_ERROR_PAT_NOT_AVAILABLE:
537  case RMF_QAMSRC_ERROR_PMT_NOT_AVAILABLE:
538  case RMF_QAMSRC_ERROR_PROGRAM_NUMBER_INVALID:
539  case RMF_QAMSRC_ERROR_PROGRAM_NUMBER_INVALID_ON_PAT_UPDATE:
540  errorCode = "102";
541  break;
542 
543  case RMF_QAMSRC_ERROR_UNRECOVERABLE_ERROR:
544  errorCode = "103";
545  break;
546 
547  case RMF_QAMSRC_ERROR_TUNER_NOT_LOCKED:
548  case RMF_QAMSRC_ERROR_TUNE_FAILED:
549  errorCode = "104";
550  break;
551  default:
552  inputErr = "Service Unavailable";
553  errorCode = "106";
554  break;
555  }
556  errorMsg = errorCode + ":Error:" + inputErr;
557  }
558  else if (m_isDVRAsset)
559  {
560  //since its mDVR and HNSource is used, send the eror code as same as what you get.. :)
561  errorMsg = inputErr;
562  }
563 
564  LOG_INFO ("The Error String set is %s", errorMsg.c_str());
565  setMediaErrorMessage(errorMsg);
566 }
567 #endif /* ENABLE_DIRECT_QAM */
568 
569 void MediaPlayerDLNA::fetchHeaders() {
570 #ifdef USE_VODSRC
571  m_progressTimer.startOneShot(1.0);
572  return;
573 #else
574  RequestInfo request;
575  request.url = m_url;
576  request.headers.push_back("getAvailableSeekRange.dlna.org: 1");
577  fetchOnWorkerThread(request);
578 #endif /* USE_VODSRC */
579 }
580 
581 void MediaPlayerDLNA::fetchOnWorkerThread(const RequestInfo& request) {
582  // TODO: fetch on worker thread
583  ResponseInfo response;
584  fetchWithCurl(request, response);
585  onReplyFinished(response);
586 }
587 
588 void MediaPlayerDLNA::fetchWithCurl(
589  const RequestInfo& request, ResponseInfo& response) {
590  LOG_VERBOSE("curl request for url: %s", request.url.c_str());
591  LOG_VERBOSE("headers:");
592  for (headers_t::const_iterator cit = request.headers.begin();
593  cit != request.headers.end(); ++cit) {
594  const std::string& header = *cit;
595  LOG_VERBOSE("\t%s", header.c_str());
596  }
597 
598  CURLcode res = CURLE_OK;
599  CURL *curl_handle = NULL;
600 
601  std::string headers_buf;
602  std::string payload_buf;
603 
604  curl_handle = curl_easy_init();
605  CURL_EASY_SETOPT(curl_handle, CURLOPT_URL, request.url.c_str());
606  CURL_EASY_SETOPT(curl_handle, CURLOPT_FOLLOWLOCATION, 1);
607  CURL_EASY_SETOPT(curl_handle, CURLOPT_TIMEOUT, kCurlTimeoutInSeconds);
608  CURL_EASY_SETOPT(curl_handle, CURLOPT_HEADERFUNCTION, write_callback);
609  CURL_EASY_SETOPT(curl_handle, CURLOPT_HEADERDATA,
610  reinterpret_cast<void *>(&headers_buf));
611  // We're not interested in body, but if we do
612  // curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_callback);
613  // curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&payload_buf);
614  // curl_easy_setopt(curl_handle, CURLOPT_HTTPGET, 1L);
615  CURL_EASY_SETOPT(curl_handle, CURLOPT_NOBODY, 1);
616  CURL_EASY_SETOPT(curl_handle, CURLOPT_HEADER, 1);
617  CURL_EASY_SETOPT(curl_handle, CURLOPT_NOPROGRESS, 1);
618  CURL_EASY_SETOPT(curl_handle, CURLOPT_NOSIGNAL, 1);
619  // curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1);
620 
621  if (!request.headers.empty()) {
622  struct curl_slist *headers = NULL;
623  for (headers_t::const_iterator cit = request.headers.begin();
624  cit != request.headers.end(); ++cit) {
625  const std::string& header = *cit;
626  headers = curl_slist_append(headers, header.c_str());
627  }
628  CURL_EASY_SETOPT(curl_handle, CURLOPT_HTTPHEADER, headers);
629  }
630 
631  res = curl_easy_perform(curl_handle);
632 
633  if (res != CURLE_OK) {
634  LOG_ERROR("curl failed with result: %d", res);
635  response.http_code = -1;
636  curl_easy_cleanup(curl_handle);
637  return;
638  }
639 
640  long httpCode = -1;
641  if (CURLE_OK == curl_easy_getinfo(curl_handle, _CURLINFO_RESPONSE_CODE, &httpCode))
642  response.http_code = httpCode;
643  else
644  response.http_code = -1;
645 
646  response.url = request.url;
647  response.payload = payload_buf;
648  response.headers = split_string(headers_buf, '\n', response.headers);
649 
650  LOG_VERBOSE("curl got response for url: %s", response.url.c_str());
651  LOG_VERBOSE("headers:");
652  for (headers_t::const_iterator cit = response.headers.begin();
653  cit != response.headers.end(); ++cit) {
654  const std::string& header = *cit;
655  LOG_VERBOSE("\t%s", header.c_str());
656  }
657 
658  curl_easy_cleanup(curl_handle);
659 }
660 
661 void MediaPlayerDLNA::time_to_hms(
662  float time, unsigned& h, unsigned& m, float& s) {
663  if (time < 0)
664  time = 0;
665 
666  h = time / 3600;
667  m = (time - h * 3600) / 60;
668  s = time - h * 3600 - m * 60;
669 }
670 
671 void MediaPlayerDLNA::fetchHeadersForTrickMode(float speed, double pos) {
672 #ifdef USE_VODSRC
673  (void)speed;
674  (void)pos;
675  return;
676 #else
677  m_fetchTrickModeHeaders = true;
678 
679  /* reset the flag before sending the speed command */
680  if (speed != 0.0)
681  {
682  LOG_INFO("MediaPlayerDLNA: fetchHeadersForTrickMode speed change request. So reset the paused flag if any..");
683  m_isVODPauseRequested = false;
684  }
685 
686  char speed_str[64];
687  char time_str[64];
688 
689  errno_t safec_rc =sprintf_s(speed_str, sizeof(speed_str), "speed=%f", speed);
690  if(safec_rc < EOK) {
691  ERR_CHK(safec_rc);
692  }
693  LOG_INFO("MediaPlayerDLNA: fetchHeadersForTrickMode speed: [%s]", speed_str);
694 
695  unsigned h = 0, m = 0;
696  float s = 0;
697  time_to_hms(pos, h, m, s);
698 
699  safec_rc =sprintf_s(time_str, sizeof(time_str), "npt=%02u:%02u:%.2f-", h, m, s);
700  if(safec_rc < EOK) {
701  ERR_CHK(safec_rc);
702  }
703  LOG_INFO("MediaPlayerDLNA: fetchHeadersForTrickMode position: [%s] (%f)", time_str, pos);
704 
705  RequestInfo request;
706  request.url = m_url;
707  request.headers.push_back(std::string("getAvailableSeekRange.dlna.org: 1"));
708  request.headers.push_back(std::string("PlaySpeed.dlna.org: ") + speed_str);
709  request.headers.push_back(std::string("TimeSeekRange.dlna.org: ") + time_str);
710 
711  fetchOnWorkerThread(request);
712 #endif /* USE_VODSRC */
713 }
714 
715 void MediaPlayerDLNA::onReplyError() {
716  setMediaErrorMessage("VOD:: MediaStreamer is not reachable");
717  loadingFailed(MediaPlayer::RMF_PLAYER_NETWORKERROR);
718  m_progressTimer.startOneShot(0);
719 }
720 
721 void MediaPlayerDLNA::onReplyFinished(const ResponseInfo& response) {
722  const headers_t& headers = response.headers;
723  LOG_TRACE("Load finished with http_code: %d", response.http_code);
724  if (response.http_code < 0) {
725  onReplyError();
726  return;
727  }
728 
729  if (m_progressTimer.isActive())
730  m_progressTimer.stop();
731 
732  std::string seek_header;
733  std::string speed_header;
734  std::string adHeader;
735  find_header(headers, HEADER_NAME_VODADINSERTION_STATUS, adHeader);
736  if (!adHeader.empty()) {
737  LOG_INFO ("Ad_header: %s", adHeader.c_str());
738  /* The response will be either "started" or "completed" */
739  if (std::string::npos != adHeader.find("started"))
740  {
741  LOG_INFO ("Ad is being played; could not honor the trick request");
742  if (1.0 != m_playbackRate)
743  {
744  LOG_INFO ("Ad Started during trick it seems; switch to 1.0f");
745  m_playbackRate = 1.0f;
746  m_playerClient->rateChanged();
747  }
748  m_rmfMediaWarnDesc = std::string("TRICK_MODE_NOT_ALLOWED");
749  m_rmfMediaWarnData = 1; /* Speed */
750  m_playerClient->mediaWarningReceived();
751 
752  if ((m_paused) && (m_source))
753  {
754  float speed = 0.0; /* Pause is called internally when speed is called with 0 */
755  double time = 0.0; /* Time is not used when the speed is 0.0; */
756  g_print ("Current state is paused; So update the hnsource for the timeouts..\n");
757  m_isVODPauseRequested = true;
758  m_source->play (speed, time);
759  }
760  }
761  else
762  LOG_TRACE ("No Opp as og now for this ad insertion %s", adHeader.c_str());
763  } else {
764  bool postTimeChanged = true;
765  unsigned int seekTime = 0;
766  // TODO: backport changes from qtwebkit/Source/WebCore/platform/graphics/dlna/MediaPlayerPrivateDLNA.cpp
767  find_header(headers, HEADER_NAME_SEEK_RANGE, seek_header);
768  if (!seek_header.empty() && (!m_EOSPending)) {
769 
770  LOG_INFO("seek_header: %s", seek_header.c_str());
771  // Split the response to get the NPT value
772  std::vector<std::string> first_split;
773  split_string(seek_header, '=', first_split);
774  LOG_TRACE("first_split ok");
775  std::string npt_str = first_split.at(1);
776  LOG_INFO("npt_str: %s", npt_str.c_str());
777  // The start time is in the format of hh:mm:ss per DLNA standard.
778  std::vector<std::string> second_split;
779  split_string(npt_str, ':', second_split);
780  // The length must be 3 bcoz the format hh:mm:ss per standard
781  if (3 == second_split.size()) {
782  LOG_TRACE("second_split ok");
783  int hour = atoi(second_split.at(0).c_str());
784  int minute = atoi(second_split.at(1).c_str());
785  int second = atoi(second_split.at(2).c_str());
786  LOG_TRACE("hour: %d, min: %d, second: %d", hour, minute, second);
787  seekTime = (hour * 3600) + (minute * 60) + second;
788  LOG_INFO ("MediaPlayerDLNA:: Received lastStartNPT is %u", seekTime);
789 
790  if (m_VODKeepPipelinePlaying) {
791  if (m_isVODAsset && (seekTime == (RMF_VOD_BAD_START_POSITION_VAL/1000u)))
792  {
793  LOG_INFO("MediaPlayerDLNA:: VOD EOS Pending");
794  m_EOSPending = true;
795  }
796  }
797  }
798  }
799  /***/
800  find_header(headers, HEADER_NAME_PLAYSPEED, speed_header);
801  if (!speed_header.empty() && (!m_EOSPending))
802  {
803  LOG_TRACE("speed_header: %s", speed_header.c_str());
804  std::vector<std::string> speed_vec;
805  split_string(speed_header, '=', speed_vec);
806  std::string new_param = speed_vec.at(1);
807  LOG_INFO ("MediaPlayerDLNA:: Header Response:: Speed Header is = %s\n", new_param.c_str());
808 
809  /* Reset the progressTime as it is going to restart the timer now with new speed */
810  m_currentProgressTime = 0;
811  float speed = atof(new_param.c_str());
812 
813 
814  if (!m_isVOD5XHackEnabled)
815  {
816  if (0 == speed)
817  {
818  m_paused = true;
819  speed = 1.0;
820  }
821  else
822  m_paused = false;
823 
824  if (m_playbackRate != speed)
825  {
826  m_playbackRate = speed;
827  m_playerClient->rateChanged();
828  }
829 
830  LOG_INFO ("MediaPlayerDLNA:: Header Response:: Asset [VOD] speed: [%f]\n", m_playbackRate);
831  }
832  else
833  {
834  if ((m_isVODPauseRequested) && (0 == speed))
835  {
836  speed = 1.0;
837  m_paused = true;
838  if (speed != m_playbackRate)
839  {
840  m_playbackRate = speed;
841  m_playerClient->rateChanged();
842  }
843  }
844  else if ((m_isVODPauseRequested) && (0 != speed))
845  {
846  speed = 1.0;
847  m_paused = true;
848  if (speed != m_playbackRate)
849  {
850  m_playbackRate = speed;
851  m_playerClient->rateChanged();
852  }
853  postTimeChanged = false;
854  LOG_WARNING("MediaPlayerPrivateDLNA:: Header Response:: Ignore this [%s] response as it is invalid at this point in time", new_param.c_str());
855  }
856  else
857  {
858  m_paused = false;
859  if (0 == speed)
860  {
861  LOG_WARNING("MediaPlayerPrivateDLNA:: Header Response received for the Pause request after we sent other trick mode command.");
862  speed = 1.0;
863  postTimeChanged = false;
864  }
865  else if ((m_isVODSeekRequested) && (speed != 1.0))
866  {
867  LOG_WARNING("MediaPlayerPrivateDLNA:: Header Response received for the trick modes after the seek command sent.");
868  speed = 1.0;
869  postTimeChanged = false;
870  }
871  else
872  {
873  m_isVODSeekRequested = false;
874  if (speed != m_playbackRate)
875  {
876  m_playbackRate = speed;
877  m_playerClient->rateChanged();
878  }
879  LOG_WARNING("MediaPlayerPrivateDLNA:: Header Response:: Asset [VOD] speed: [%f]\n", m_playbackRate);
880  }
881  }
882  }
883 
884  }
885  /* Update the time & post a event to WebKit */
886  if(postTimeChanged)
887  {
888  /* Update the Base Time as it is associated with the speed */
889  m_baseSeekTime = seekTime;
890  m_playerClient->timeChanged();
891  }
892  }
893 
894  if (!m_paused) {
895  m_progressTimer.startOneShot(1.0);
896  }
897 }
898 
899 void MediaPlayerDLNA::onProgressTimerTimeout() {
900  m_currentProgressTime += m_playbackRate;
901 
902  //LOG_VERBOSE("MediaPlayerDLNA::onProgressTimerTimeout: %f", m_currentProgressTime);
903 
904  // This logic may be extended for Live and DVR also; But for VOD; the rate is
905  // 8.0 by the vod server; so to avoid wrong calculation, use conditional check
906  if (m_isVODAsset) {
907  if ((m_playbackRate == 4.0) || (m_playbackRate == -4.0))
908  m_currentProgressTime += m_playbackRate;
909  }
910 
911  m_progressTimer.startOneShot(1.0);
912 
913  if ((m_playbackRate < 0) && (playbackPosition() == 0)) {
914  m_restartPlaybackCount++;
915  if (m_restartPlaybackCount > RMF_VOD_BEGIN_PLAYBACK) {
916  m_restartPlaybackCount = 0;
917  ended();
918  }
919  }
920 }
921 
922 bool MediaPlayerDLNA::rmf_load(const std::string& httpUrl) {
923  LOG_INFO("LOAD IS CALLED (%s)", httpUrl.c_str());
924 
925  char *pVOD5XHack = NULL;
926  pVOD5XHack = getenv("RMF_VOD_5X_MITIGATION");
927  errno_t safec_rc = -1;
928  int ind = -1;
929 
930  if (pVOD5XHack) {
931  safec_rc = strcasecmp_s("TRUE", strlen("TRUE"), pVOD5XHack, &ind);
932  ERR_CHK(safec_rc);
933  if((safec_rc == EOK) && (ind == 0)) {
934  LOG_WARNING("RMF_VOD_5X_MITIGATION is set to TRUE..\n");
935  m_isVOD5XHackEnabled = true;
936  }
937  }
938 
939  if (httpUrl.empty()) {
940  LOG_ERROR("Empty URL, skipping RMF pipeline construction");
941  return false;
942  }
943 
944  if (m_source) {
945  LOG_ERROR("It seems like, It is loaded was already but not stopped yet. "
946  "This is under worst case.. Just return or call stop internally");
947  rmf_stop();
948  return false;
949  }
950 
951  m_url = httpUrl;
952  /* Set it to TRUE as a backup */
953  m_isMusicOnlyAsset = true;
954 
955  char url[1024];
956 #ifdef ENABLE_DIRECT_QAM
957  char *p;
958  char ocapUrl[32];
959  uint c, len;
960  if (m_url.find("ocap://") != std::string::npos) {
961  safec_rc = strcpy_s(url, sizeof(url), m_url.c_str());
962  if(safec_rc != EOK) {
963  ERR_CHK(safec_rc);
964  return false;
965  }
966  p= strstr(url,"ocap://0x");
967  len= strlen("ocap://0x");
968  c= p[len];
969  while(((c >= '0') && (c <= '9')) ||
970  ((c >= 'a') && (c <= 'f')) ||
971  ((c >= 'A') && (c <= 'F')))
972  {
973  c= p[++len];
974  if (len >= (sizeof(ocapUrl) - 1))
975  break;
976  }
977  safec_rc = strncpy_s(ocapUrl, sizeof(ocapUrl), p, len);
978  if(safec_rc != EOK) {
979  ERR_CHK(safec_rc);
980  return false;
981  }
982  ocapUrl[len]= '\0';
983  LOG_INFO("QAM service: %s", ocapUrl);
984 
985  m_hnsource = NULL;
986  if (true == RMFQAMSrc::useFactoryMethods()) {
987  m_source = RMFQAMSrc::getQAMSourceInstance(ocapUrl);
988  } else {
989  m_source = new RMFQAMSrc();
990  }
991  }
992  else if (m_url.find("tune://") != std::string::npos) {
993  strcpy(url, m_url.c_str());
994  m_hnsource = NULL;
995  if (true == RMFQAMSrc::useFactoryMethods()) {
996  m_source = RMFQAMSrc::getQAMSourceInstance(m_url.c_str());
997  } else {
998  m_source = new RMFQAMSrc();
999  }
1000  RMFQAMSrc::init_platform();
1001  }
1002 #ifdef IPPV_CLIENT_ENABLED
1003  else if (m_url.find("ippv://") != std::string::npos) {
1004  safec_rc = strcpy_s(url, sizeof(url), m_url.c_str());
1005  if(safec_rc != EOK) {
1006  ERR_CHK(safec_rc);
1007  return false;
1008  }
1009  p= strstr(url,"ippv://0x");
1010  len= strlen("ippv://0x");
1011  c= p[len];
1012  while(((c >= '0') && (c <= '9')) ||
1013  ((c >= 'a') && (c <= 'f')) ||
1014  ((c >= 'A') && (c <= 'F'))) {
1015  c= p[++len];
1016  if (len >= (sizeof(ocapUrl) - 1))
1017  break;
1018  }
1019  safec_rc = strncpy_s(ocapUrl, sizeof(ocapUrl), p, len);
1020  if(safec_rc != EOK) {
1021  ERR_CHK(safec_rc);
1022  return false;
1023  }
1024  ocapUrl[len]= '\0';
1025  LOG_INFO("IPPV service: %s", ocapUrl);
1026  safec_rc = strcpy_s(url, sizeof(url), ocapUrl);
1027  if(safec_rc != EOK) {
1028  ERR_CHK(safec_rc);
1029  return false;
1030  }
1031  m_hnsource = NULL;
1032  m_source = new RMFiPPVSrc();
1033  }
1034 #endif
1035 #ifdef USE_VODSRC
1036  else if (m_url.find("vod://") != std::string::npos) {
1037  safec_rc = strcpy_s(url, sizeof(url), m_url.c_str());
1038  if(safec_rc != EOK) {
1039  ERR_CHK(safec_rc);
1040  return false;
1041  }
1042  p= strstr(url,"vod://");
1043  char *tempstr = strchr(p,'&');
1044  //char *tempstr1 = strchr(p,'\0');
1045  if(tempstr != NULL) {
1046  safec_rc = strncpy_s(ocapUrl, sizeof(ocapUrl), p, tempstr-p);
1047  if(safec_rc != EOK) {
1048  ERR_CHK(safec_rc);
1049  return false;
1050  }
1051  ocapUrl[tempstr-p]= '\0';
1052  } else {
1053  safec_rc = strcpy_s(ocapUrl, sizeof(ocapUrl), p);
1054  if(safec_rc != EOK) {
1055  ERR_CHK(safec_rc);
1056  return false;
1057  }
1058  }
1059  LOG_INFO("vod service: %s", ocapUrl);
1060  safec_rc = strcpy_s(url, sizeof(url), ocapUrl);
1061  if(safec_rc != EOK) {
1062  ERR_CHK(safec_rc);
1063  return false;
1064  }
1065  m_hnsource = NULL;
1066  m_source = new RMFVODSrc();
1067  m_VODKeepPipelinePlaying = false;
1068  }
1069 #endif
1070  else {
1071 #endif
1072 
1073  safec_rc = strcpy_s(url, sizeof(url), m_url.c_str());
1074  if(safec_rc != EOK) {
1075  ERR_CHK(safec_rc);
1076  return false;
1077  }
1078  m_source = new HNSource();
1079  m_hnsource = dynamic_cast<HNSource *>(m_source);
1080 
1081 #ifdef ENABLE_DIRECT_QAM
1082  }
1083 #endif
1084 
1085  if(NULL == m_source) {
1086  LOG_ERROR("Source create failed");
1087  m_videoState = MediaPlayer::RMF_VIDEO_BUFFER_HAVENOTHING;
1088  notifyError(0, "Service unavailable");
1089  return false;
1090  }
1091 
1092  if (m_url.find("vod://") != std::string::npos) {
1093  m_isVODAsset = true;
1094  }
1095 #ifdef ENABLE_DIRECT_QAM
1096  else if ((m_url.find("tune://") != std::string::npos) || (m_url.find("ocap://") != std::string::npos)) {
1097  m_isLiveAsset = true;
1098  }
1099  else if (m_url.find("ippv://") != std::string::npos) {
1100  m_isPPVAsset = true;
1101  }
1102  else /* This plugin can play ocap://, vod://, ppv:// and DVR ONLY. so if none of the above, we can consider that it is of DVR */
1103  m_isDVRAsset = true;
1104 #endif
1105 
1106  if (m_source->init() != RMF_RESULT_SUCCESS) {
1107  m_errorMsg = "Failed to initialize source";
1108  m_videoState = MediaPlayer::RMF_VIDEO_BUFFER_HAVENOTHING;
1109  LOG_ERROR("%s", m_errorMsg.c_str());
1110  loadingFailed(MediaPlayer::RMF_PLAYER_DECODEERROR);
1111  return false;
1112  }
1113 
1114  m_source->setEvents(m_events);
1115 
1116  if(m_source->open(url, NULL) != RMF_RESULT_SUCCESS) {
1117  m_errorMsg = "Failed to open source";
1118  m_videoState = MediaPlayer::RMF_VIDEO_BUFFER_HAVENOTHING;
1119  LOG_ERROR("%s", m_errorMsg.c_str());
1120  loadingFailed(MediaPlayer::RMF_PLAYER_DECODEERROR);
1121  return false;
1122  }
1123 
1124  m_sink = new MediaPlayerSink();
1125 
1126  if(NULL == m_sink) {
1127  m_errorMsg = "Sink create failed";
1128  m_videoState = MediaPlayer::RMF_VIDEO_BUFFER_HAVENOTHING;
1129  LOG_ERROR("%s", m_errorMsg.c_str());
1130  loadingFailed(MediaPlayer::RMF_PLAYER_DECODEERROR);
1131  return false;
1132  }
1133 
1134  if (m_sink->init() != RMF_RESULT_SUCCESS) {
1135  m_errorMsg = "Failed to initialize video sink";
1136  m_videoState = MediaPlayer::RMF_VIDEO_BUFFER_HAVENOTHING;
1137  LOG_ERROR("%s", m_errorMsg.c_str());
1138  loadingFailed(MediaPlayer::RMF_PLAYER_DECODEERROR);
1139  return false;
1140  }
1141  m_sink->setEvents(m_events_sink);
1142 
1143  if (getenv("USE_SINK_DUMP")) {
1144  LOG_INFO("######################### Adding dump file sink ##########################");
1145  m_dfsink = new DumpFileSink();
1146  }
1147 
1148  if (m_dfsink) {
1149  char url[1024];
1150  char ipaddr[20];
1151  char location[100];
1152  safec_rc = strcpy_s(url, sizeof(url), m_url.c_str());
1153  if(safec_rc != EOK) {
1154  ERR_CHK(safec_rc);
1155  return false;
1156  }
1157  safec_rc = strcpy_s(ipaddr, sizeof(ipaddr), "127.0.0.1");
1158  if(safec_rc != EOK) {
1159  ERR_CHK(safec_rc);
1160  return false;
1161  }
1162  char* ip_start_pos = strstr(url, "http://") + strlen("http://");
1163  if (NULL != ip_start_pos) {
1164  char* ip_end_pos = strstr(ip_start_pos, ":");
1165  if (NULL != ip_end_pos) {
1166  safec_rc = strncpy_s(ipaddr, sizeof(ipaddr), ip_start_pos, ip_end_pos - ip_start_pos);
1167  if(safec_rc != EOK) {
1168  ERR_CHK(safec_rc);
1169  return false;
1170  }
1171  ipaddr[ip_end_pos - ip_start_pos] = 0;
1172  }
1173  }
1174  safec_rc = sprintf_s(location, sizeof(location), "/opt/SNK_IN_%s.ts", ipaddr);
1175  if(safec_rc < EOK) {
1176  ERR_CHK(safec_rc);
1177  return false;
1178  }
1179  if (m_dfsink->init() != RMF_RESULT_SUCCESS) {
1180  LOG_ERROR("Failed to initialize fd sink");
1181  return false;
1182  }
1183  m_dfsink->setLocation(location);
1184  m_dfsink->setSource(m_source);
1185  }
1186 
1187  m_sink->setSource(m_source);
1188  m_sink->setHaveVideoCallback(mediaPlayerPrivateHaveVideoCallback, this);
1189  m_sink->setHaveAudioCallback(mediaPlayerPrivateHaveAudioCallback, this);
1190  m_sink->setEISSDataCallback(mediaPlayerPrivateEISSDataCallback, this);
1191  m_sink->setVideoPlayingCallback(mediaPlayerPrivateVideoNotifyFirstFrameCallback, this);
1192  m_sink->setAudioPlayingCallback(mediaPlayerPrivateAudioNotifyFirstFrameCallback, this);
1193  m_sink->setMediaWarningCallback(mediaPlayerPrivateNotifyMediaWarningCallback, this);
1194  m_sink->setPmtUpdateCallback(mediaPlayerPrivateNotifyPmtUpdateCallback, this);
1195  m_sink->setLanguageChangeCallback(mediaPlayerLanguageChangeCallback, this);
1196 
1197 #ifdef USE_VODSRC
1198  if (m_isVODAsset) {
1199  m_source->setSpeed(1.0f);
1200  m_source->setMediaTime(0.0);
1201  }
1202 #endif /* USE_VODSRC */
1203 
1204  if (!m_delayingLoad)
1205  commitLoad();
1206  else
1207  LOG_INFO("Not committing load");
1208 
1209  LOG_INFO("LOAD FINISHED");
1210  return true;
1211 }
1212 
1213 void MediaPlayerDLNA::commitLoad() {
1214  ASSERT(!m_delayingLoad);
1215  LOG_INFO("Committing load.");
1216  updateStates();
1217 }
1218 
1219 float MediaPlayerDLNA::playbackPosition() const {
1220  if (m_isVODAsset) {
1221  float pos = m_baseSeekTime + m_currentProgressTime;
1222  if (pos >= 0)
1223  return pos;
1224  else
1225  return 0.f;
1226  } else {
1227  double pos = m_currentPosition;
1228 #ifdef ENABLE_DIRECT_QAM
1229  if (!m_isDVRAsset) {
1230  if ((m_sink) && (m_sink->getMediaTime(pos) != RMF_RESULT_SUCCESS)) {
1231  LOG_ERROR("Failed to get playback position, return previous: %f", m_currentPosition);
1232  return m_currentPosition;
1233  }
1234  } else {
1235 #endif /* ENABLE_DIRECT_QAM */
1236  if (m_allowPositionQueries && (!m_source || m_source->getMediaTime(pos) != RMF_RESULT_SUCCESS)) {
1237  LOG_ERROR("Failed to get playback position, return previous: %f", m_currentPosition);
1238  return m_currentPosition;
1239  }
1240 #ifdef ENABLE_DIRECT_QAM
1241  }
1242 #endif /* ENABLE_DIRECT_QAM */
1243  return static_cast<float>(pos);
1244  }
1245 }
1246 
1247 void MediaPlayerDLNA::prepareToPlay() {
1248  if (m_delayingLoad) {
1249  m_delayingLoad = false;
1250  commitLoad();
1251  }
1252 }
1253 
1254 void MediaPlayerDLNA::rmf_play() {
1255  LOG_INFO("PLAY IS CALLED");
1256 
1257  if (!m_source) {
1258  LOG_WARNING("No source, skip play.");
1259  return;
1260  }
1261 
1262  m_isEndReached = false;
1263  m_paused = false;
1264 
1265  if ((m_networkBufferSize) && (m_isVOnlyOnce)) {
1266  m_sink->setNetWorkBufferSize(m_networkBufferSize);
1267  }
1268 
1269  if (m_VODKeepPipelinePlaying) {
1270  if (m_isVODAsset) {
1271  if (m_EOSPending) {
1272  LOG_WARNING("Play cannot be done now as the VOD Server posted that it is sending EOS shortly");
1273  return;
1274  }
1275  if (!m_isAOnlyOnce && m_allowPositionQueries)
1276  fetchHeadersForTrickMode(rmf_getRate(), m_baseSeekTime);
1277  }
1278  }
1279 
1280  if (m_source->play() == RMF_RESULT_SUCCESS) {
1281  LOG_INFO("Play");
1282 
1283  /* Update the time at which the asset was paused */
1284  m_currentPosition = rmf_getCurrentTime();
1285  m_pausedInternal = false;
1286  } else {
1287  LOG_ERROR("Play failed for some unknown reason..");
1288  loadingFailed(MediaPlayer::RMF_PLAYER_EMPTY);
1289  }
1290 
1291 #ifdef IPPV_CLIENT_ENABLED
1292  if (m_isPPVAsset) {
1293  unsigned int eIdValue = 0x00;
1294  char url[1024];
1295  char *p;
1296  uint c, len;
1297  char eid[32];
1298 
1299  errno_t safec_rc = strcpy_s(url, sizeof(url), m_url.c_str());
1300  if(safec_rc != EOK) {
1301  ERR_CHK(safec_rc);
1302  return;
1303  }
1304  p= strstr(url,"token=");
1305  len= 6;
1306  if (p != NULL) {
1307  c= p[len];
1308  while ((c >= '0') && (c <= '9')) {
1309  c= p[++len];
1310  if (len >= (sizeof(eid) - 1))
1311  break;
1312  }
1313  safec_rc = strncpy_s(eid, sizeof(eid), p+6, len-6);
1314  if(safec_rc != EOK) {
1315  ERR_CHK(safec_rc);
1316  return;
1317  }
1318 
1319  eid[len-6]= '\0';
1320  eIdValue = atoi(eid);
1321  LOG_INFO("play:: ippv asset: EID='%s',%d", eid, eIdValue);
1322  }
1323 
1324  if (0x00 != eIdValue) {
1325  int rc = ((RMFiPPVSrc*)m_source)->purchasePPVEvent( eIdValue );
1326  if ( 0 != rc ) {
1327  LOG_ERROR("PPV event purchase failed");
1328  /*TODO:: Handle error */
1329  } else {
1330  LOG_INFO("PPV event purchase succeeded");
1331  }
1332  } else {
1333  LOG_INFO("Already purchased PPV event");
1334  }
1335  }
1336 #endif //IPPV_CLIENT_ENABLED
1337 }
1338 
1339 void MediaPlayerDLNA::rmf_pause() {
1340  LOG_INFO("PAUSE IS CALLED");
1341  if (!m_source)
1342  return;
1343  if (m_isEndReached)
1344  return;
1345 
1346 #ifdef ENABLE_DIRECT_QAM
1347  /* Trick mode is allowed only for VOD and mDVR */
1348  if (!(m_isDVRAsset | m_isVODAsset))
1349  return;
1350 #endif /* ENABLE_DIRECT_QAM */
1351 
1352  if (!m_pausedInternal) {
1353  float speed = 0.0; // Pause is called internally when speed is called with 0
1354  double time = 0.0; // Time is not used when the speed is 0.0
1355 
1356  if (m_VODKeepPipelinePlaying) {
1357  if (m_isVODAsset) {
1358  if (m_EOSPending) {
1359  LOG_WARNING("Pause cannot be done now as the VOD Server posted that it is sending EOS shortly");
1360  return;
1361  }
1362 
1363  if (!m_isAOnlyOnce)
1364  {
1365  m_isVODPauseRequested = true;
1366  fetchHeadersForTrickMode(speed, time);
1367  }
1368  }
1369  }
1370 
1371 #ifdef USE_VODSRC
1372  if (m_isVODAsset) {
1373  m_source->setSpeed (speed);
1374  m_source->setMediaTime (time);
1375  } else {
1376 #endif /* USE_VODSRC */
1377 
1378  if (m_source->play(speed, time) == RMF_RESULT_SUCCESS)
1379  LOG_INFO("Pause");
1380 
1381  if (m_progressTimer.isActive())
1382  m_progressTimer.stop();
1383 
1384 #ifdef USE_VODSRC
1385  }
1386 #endif /* USE_VODSRC*/
1387 
1388  if (m_isVODAsset) {
1389 #ifdef USE_VODSRC
1390  double npt = 0.00;
1391  m_source->getMediaTime(npt);
1392  m_baseSeekTime = (long long) npt/1000;
1393 #else
1394  m_baseSeekTime = playbackPosition();
1395 #endif /* USE_VODSRC */
1396  m_currentProgressTime = 0;
1397  }
1398 
1399  m_paused = true;
1400  } else {
1401  LOG_INFO("Pause Ignored. We are still in the process of trick mode...");
1402  }
1403 }
1404 
1405 void MediaPlayerDLNA::rmf_stop() {
1406  LOG_INFO("STOP IS CALLED");
1407  if (!m_sink || !m_source)
1408  return;
1409 
1410  m_progressTimer.stop();
1411  m_allowPositionQueries = false;
1412  m_source->setEvents(NULL);
1413  m_sink->setEvents(NULL);
1414  m_source->removeEventHandler(m_events);
1415  /* Good to do this for regualr HNSource as well. So keeping it common */
1416  m_source->stop();
1417  m_source->close();
1418  m_source->term();
1419 
1420 #ifdef ENABLE_DIRECT_QAM
1421  if (m_isLiveAsset) {
1422  RMFQAMSrc *qamSrc= dynamic_cast<RMFQAMSrc *>(m_source);
1423  if ( qamSrc && (true == RMFQAMSrc::useFactoryMethods())) {
1424  //qamSrc->pause();
1425  RMFQAMSrc::freeQAMSourceInstance( qamSrc );
1426  }
1427  } else {
1428  delete m_source;
1429  }
1430 #else /* ENABLE_DIRECT_QAM */
1431  delete m_source;
1432  m_hnsource = NULL;
1433 #endif /* ENABLE_DIRECT_QAM */
1434  if (m_sink)
1435  {
1436  m_sink->term();
1437  delete m_sink;
1438  }
1439 
1440  if(m_dfsink)
1441  {
1442  m_dfsink->term();
1443  delete m_dfsink;
1444  }
1445  m_dfsink = NULL;
1446  m_sink = NULL;
1447  m_source = NULL;
1448 
1449  m_paused = true;
1450 
1451  LOG_INFO("Stop");
1452 }
1453 
1454 float MediaPlayerDLNA::rmf_getDuration() const {
1455  if (!m_source)
1456  return 0.0f;
1457 
1458  if (m_errorOccured)
1459  return 0.0f;
1460 
1461  // Media duration query failed already, don't attempt new useless queries.
1462  if (!m_mediaDurationKnown)
1463  return std::numeric_limits<float>::infinity();
1464 
1465  return m_mediaDuration;
1466 }
1467 
1468 float MediaPlayerDLNA::rmf_getCurrentTime() const {
1469  if (m_errorOccured)
1470  return 0.0f;
1471 
1472  return playbackPosition();
1473 }
1474 
1475 //
1476 // Comcast customized changes
1477 //
1478 unsigned long MediaPlayerDLNA::rmf_getCCDecoderHandle() const {
1479  if (m_sink)
1480  return m_sink->getVideoDecoderHandle();
1481 
1482  return 0;
1483 }
1484 
1485 std::string MediaPlayerDLNA::rmf_getAudioLanguages() const
1486 {
1487  if (!m_sink)
1488  return "eng";
1489  return m_sink->getAudioLanguages();
1490 }
1491 
1492 void MediaPlayerDLNA::rmf_setAudioLanguage(const std::string& audioLang) {
1493  if (m_sink)
1494  m_sink->setAudioLanguage(audioLang.c_str());
1495 
1496  return;
1497 }
1498 
1499 void MediaPlayerDLNA::rmf_setAudioMute(bool isMuted) {
1500  if (m_audioMuteStatus != isMuted)
1501  {
1502  if (m_sink)
1503  {
1504  m_sink->setAudioMute(isMuted);
1505  }
1506  m_audioMuteStatus = isMuted;
1507  }
1508 }
1509 
1510 void MediaPlayerDLNA::rmf_setEissFilterStatus (bool eissStatus)
1511 {
1512  m_eissFilterStatus = eissStatus;
1513  if(m_sink)
1514  m_sink->setEissFilterStatus (eissStatus);
1515 
1516  return;
1517 }
1518 
1519 void MediaPlayerDLNA::rmf_setVideoZoom(unsigned short zoomVal) {
1520  if (m_sink)
1521  m_sink->setVideoZoom(zoomVal);
1522 
1523  return;
1524 }
1525 
1526 void MediaPlayerDLNA::rmf_setVideoBufferLength(float bufferLength) {
1527  m_mediaDuration = bufferLength;
1528  if (m_hnsource)
1529  m_hnsource->setVideoLength(m_mediaDuration);
1530 }
1531 
1532 void MediaPlayerDLNA::rmf_setInProgressRecording(bool isInProgress) {
1533  m_isInProgressRecording = isInProgress;
1534 }
1535 
1536 void MediaPlayerDLNA::setMediaErrorMessage(const std::string& errorMsg) {
1537  m_errorMsg = errorMsg;
1538 
1539  if (m_VODKeepPipelinePlaying) {
1540  if (m_isVODAsset && (m_errorMsg == "VOD-Pause-10Min-Timeout")) {
1541  LOG_INFO("MediaPlayerDLNA::VOD EOS Pending\n");
1542  m_EOSPending = true;
1543  }
1544  }
1545 
1546  return;
1547 }
1548 
1549 // This is to seek to the live point of Linear; must be used for linear only
1550 void MediaPlayerDLNA::rmf_seekToLivePosition(void) {
1551  if (!m_source) {
1552  LOG_INFO("No source, skip seekToLivePosition.");
1553  return;
1554  }
1555 #ifdef ENABLE_DIRECT_QAM
1556  /* Trick mode is allowed only for VOD and mDVR */
1557  if (!(m_isDVRAsset | m_isVODAsset))
1558  return;
1559 #endif /* ENABLE_DIRECT_QAM */
1560 
1561  m_playbackRate = 1.0f;
1562  m_pausedInternal = false;
1563  /* Update the position as 3 sec less than the duration */
1564  m_currentPosition = m_mediaDuration - 3.0;
1565  m_allowPositionQueries = false;
1566  if (isOCAP())
1567  m_hnsource->playAtLivePosition(m_mediaDuration);
1568  else
1569  m_hnsource->setMediaTime(m_currentPosition);
1570 
1571  return;
1572 }
1573 
1574 // This is to seek to the beginning of the VOD asset; as of for VOD only. can be
1575 // extended for DVR as well
1576 void MediaPlayerDLNA::rmf_seekToStartPosition(void) {
1577  if (!m_source) {
1578  LOG_INFO("No source, skip seekToStartPosition.");
1579  return;
1580  }
1581 
1582  m_playbackRate = 1.0f;
1583  m_currentPosition = 0.0;
1584 
1585  if (m_isVODAsset) {
1586  m_currentProgressTime = 0;
1587  m_baseSeekTime = 0.0;
1588 
1589  if (m_VODKeepPipelinePlaying) {
1590  m_fetchTrickModeHeaders = false;
1591  }
1592 
1593  if (m_progressTimer.isActive())
1594  m_progressTimer.stop();
1595  }
1596 
1597  m_allowPositionQueries = false; // Will ensure that redundant position requests are avoided
1598  m_pausedInternal = false;
1599 #ifdef USE_VODSRC
1600  m_source->setSpeed (m_playbackRate);
1601  m_source->setMediaTime(m_currentPosition);
1602  /* timer is stopped at ended */
1603  m_progressTimer.startOneShot(1.0);
1604 #else
1605  if (m_isVODAsset) {
1606  m_hnsource->playAtLivePosition(m_currentPosition);
1607  }
1608  else
1609  {
1610  m_source->setMediaTime(m_currentPosition);
1611  }
1612 #endif /* USE_VODSRC */
1613  return;
1614 }
1615 
1616 std::string MediaPlayerDLNA::rmf_getMediaErrorMessage() const {
1617  return m_errorMsg;
1618 }
1619 
1620 std::string MediaPlayerDLNA::rmf_getMediaWarnDescription() const
1621 {
1622  return m_rmfMediaWarnDesc;
1623 }
1624 
1625 std::string MediaPlayerDLNA::rmf_getAvailableAudioTracks() const
1626 {
1627  if (m_rmfAudioTracks.empty())
1628  m_rmfAudioTracks = m_sink->getAudioLanguages();
1629 
1630  /* FIXME: reset m_rmfAudioTracks when PMT changes. */
1631  return m_rmfAudioTracks;
1632 }
1633 
1634 std::string MediaPlayerDLNA::rmf_getCaptionDescriptor() const
1635 {
1636  if (m_rmfCaptionDescriptor.empty() && m_sink != nullptr)
1637  m_rmfCaptionDescriptor = m_sink->getCCDescriptor();
1638 
1639  /* FIXME: reset m_rmfCaptionDescriptor when PMT changes. */
1640  return m_rmfCaptionDescriptor;
1641 }
1642 
1643 std::string MediaPlayerDLNA::rmf_getEISSDataBuffer() const
1644 {
1645  m_rmfEISSDataBuffer = m_sink->getEISSData();
1646 
1647  return m_rmfEISSDataBuffer;
1648 }
1649 int MediaPlayerDLNA::rmf_getMediaWarnData() const
1650 {
1651  return m_rmfMediaWarnData;
1652 }
1653 
1654 void MediaPlayerDLNA::rmf_setNetworkBufferSize(int bufferSize) {
1655  m_networkBufferSize = bufferSize;
1656  return;
1657 }
1658 
1659 int MediaPlayerDLNA::rmf_getVideoPid() {
1660  int video_pid = -1;
1661  if (m_sink)
1662  video_pid = m_sink->getVideoPid();
1663 
1664  return video_pid;
1665 }
1666 
1667 int MediaPlayerDLNA::rmf_getAudioPid() {
1668  int audio_pid = -1;
1669  if (m_sink)
1670  audio_pid = m_sink->getAudioPid();
1671 
1672  return audio_pid;
1673 }
1674 
1675 void MediaPlayerDLNA::rmf_setVideoKeySlot(const char* str) {
1676  if (m_sink) {
1677  m_sink->setVideoKeySlot(str);
1678  }
1679 }
1680 
1681 void MediaPlayerDLNA::rmf_setAudioKeySlot(const char* str) {
1682  if (m_sink) {
1683  m_sink->setAudioKeySlot(str);
1684  }
1685 }
1686 
1687 void MediaPlayerDLNA::rmf_deleteVideoKeySlot() {
1688  if (m_sink) {
1689  m_sink->deleteVideoKeySlot();
1690  }
1691 }
1692 
1693 void MediaPlayerDLNA::rmf_deleteAudioKeySlot() {
1694  if (m_sink) {
1695  m_sink->deleteAudioKeySlot();
1696  }
1697 }
1698 
1699 void MediaPlayerDLNA::rmf_seek(float time)
1700 {
1701  LOG_INFO("SEEK(%.2f)", time);
1702 
1703  if (m_isEndReached) {
1704  LOG_INFO("Ignore the seek() as it is being called after receiving EOS.. Duration = %f", rmf_getDuration());
1705  return;
1706  }
1707 
1708 #ifdef ENABLE_DIRECT_QAM
1709  /* Trick mode is allowed only for VOD and mDVR */
1710  if (!(m_isDVRAsset | m_isVODAsset))
1711  return;
1712 #endif /* ENABLE_DIRECT_QAM */
1713 
1714  // Avoid useless seeking.
1715  if (time == playbackPosition())
1716  return;
1717 
1718  if (m_VODKeepPipelinePlaying) {
1719  if (m_isVODAsset && (m_paused == true)) {
1720  m_pausedInternal = true;
1721  }
1722  }
1723 
1724  m_paused = false;
1725 
1726  if (!m_source) {
1727  LOG_INFO("No source, not seeking");
1728  return;
1729  }
1730 
1731  if (m_errorOccured) {
1732  LOG_INFO("Error occurred, not seeking");
1733  return;
1734  }
1735 
1736  if (m_VODKeepPipelinePlaying) {
1737  if (m_isVODAsset) {
1738  if (m_EOSPending) {
1739  LOG_INFO("Seek cannot be done now as the VOD Server posted that it is sending EOS shortly");
1740  return;
1741  }
1742 
1743  if (!m_isAOnlyOnce) {
1744  /* Below is not needed as the m_isVODSeekRequested flag will handle the stuff in the Header Response*/
1745  if (!m_isVOD5XHackEnabled)
1746  {
1747  if (1.0f != m_playbackRate)
1748  {
1749  m_playbackRate = 1.0f;
1750  m_playerClient->rateChanged();
1751  }
1752  fetchHeadersForTrickMode(m_playbackRate, time);
1753  }
1754  else
1755  {
1756  if (m_isVODPauseRequested && m_isVODRateChangeRequested)
1757  m_isVODSeekRequested = true;
1758  else
1759  m_isVODSeekRequested = false;
1760  fetchHeadersForTrickMode(1.0f, time);
1761  }
1762  }
1763  } else {
1764  m_allowPositionQueries = false; // Will ensure that redundant position requests are avoided
1765  }
1766  } else {
1767  m_allowPositionQueries = false; // Will ensure that redundant position requests are avoided
1768  }
1769 
1770 #ifdef USE_VODSRC
1771  double fTime = time;
1772  if (m_isVODAsset)
1773  fTime = time * 1000;
1774  if (m_source->setMediaTime(fTime) == RMF_RESULT_SUCCESS)
1775 #else
1776  if (m_source->setMediaTime(time) == RMF_RESULT_SUCCESS)
1777 #endif /* USE_VODSRC */
1778  {
1779  if (1.0f != m_playbackRate) {
1780  m_playbackRate = 1.0f;
1781  m_playerClient->rateChanged();
1782  }
1783 
1784  if (m_VODKeepPipelinePlaying) {
1785  if (m_isVODAsset) {
1786  /* Updating the baseSeekTime should be avoided here as the HEAD Response will take care. */
1787  /* BUT, Due to DELIA-8360, we keep this for now */
1788  m_baseSeekTime = time;
1789  m_currentProgressTime = 0;
1790 
1791  m_currentPosition = time;
1792  LOG_INFO("m_seeking - no change - fake seek");
1793  m_seeking = false;
1794  m_playerClient->timeChanged();
1795  m_pausedInternal = false;
1796  } else {
1797  m_currentPosition = time;
1798  LOG_INFO("m_seeking = true");
1799  m_seeking = true;
1800  m_pausedInternal = false;
1801  m_currentProgressTime = 0;
1802  m_baseSeekTime = time;
1803  if (m_progressTimer.isActive())
1804  m_progressTimer.stop();
1805  }
1806  } else {
1807  m_currentPosition = time;
1808  LOG_INFO("m_seeking = true");
1809  m_seeking = true;
1810  m_currentProgressTime = 0;
1811  m_baseSeekTime = time;
1812  m_pausedInternal = false;
1813 #ifdef USE_VODSRC
1814  double npt = 0.00;
1815  m_source->getMediaTime(npt);
1816  m_baseSeekTime = (long long) npt/1000;
1817  LOG_INFO("BaseTime that we received is = %f", m_baseSeekTime);
1818  m_seeking = false;
1819  m_playerClient->timeChanged();
1820 #else /* USE_VODSRC */
1821  if (m_progressTimer.isActive())
1822  m_progressTimer.stop();
1823 #endif /* USE_VODSRC */
1824  }
1825  } else {
1826  LOG_ERROR("Seek failed");
1827  updateStates(); // tell the HTML element we're not seeking anymore
1828  }
1829 }
1830 
1831 bool MediaPlayerDLNA::rmf_isPaused() const {
1832  if (m_isEndReached)
1833  return true;
1834 
1835  return m_paused;
1836 }
1837 
1838 bool MediaPlayerDLNA::rmf_isSeeking() const {
1839  return m_seeking;
1840 }
1841 
1842 void MediaPlayerDLNA::notifyPresenceOfVideo()
1843 {
1844  /* Since Presence of Video is notified, this cannot be of Music Only channel. */
1845  m_isMusicOnlyAsset = false;
1846 }
1847 
1848 void MediaPlayerDLNA::notifyPlayerOfEISSData()
1849 {
1850  if (m_onEISSDUpdateHandler)
1851  g_source_remove(m_onEISSDUpdateHandler);
1852 
1853  m_onEISSDUpdateHandler = g_timeout_add(0, [](gpointer data) -> gboolean {
1854  MediaPlayerDLNA& self = *static_cast<MediaPlayerDLNA*>(data);
1855  self.m_onEISSDUpdateHandler = 0;
1856  self.onEISSDUpdate();
1857  return G_SOURCE_REMOVE;
1858  }, this);
1859 }
1860 
1861 void MediaPlayerDLNA::notifyPlayerOfFirstVideoFrame() {
1862  if (m_isVOnlyOnce)
1863  LOG_INFO("Received First Video Frame for the playback of the URL=%s with "
1864  "play speed = %f time position = %f",
1865  m_url.c_str(),
1866  m_playbackRate,
1867  m_currentPosition);
1868  else
1869  LOG_INFO("Received First Video Frame for the trickmode in the URL=%s with "
1870  "play speed = %f time position = %f",
1871  m_url.c_str(),
1872  m_playbackRate,
1873  m_currentPosition);
1874 
1875  m_allowPositionQueries = true;
1876  if (m_onFirstVideoFrameHandler)
1877  g_source_remove(m_onFirstVideoFrameHandler);
1878  m_onFirstVideoFrameHandler = g_timeout_add(0, [](gpointer data) -> gboolean {
1879  MediaPlayerDLNA& self = *static_cast<MediaPlayerDLNA*>(data);
1880  self.m_onFirstVideoFrameHandler = 0;
1881  self.onFirstVideoFrame();
1882  return G_SOURCE_REMOVE;
1883  }, this);
1884 }
1885 
1886 void MediaPlayerDLNA::notifyPMTUpdate() {
1887  if(m_pmtUpdate)
1888  {
1889  LOG_INFO("MediaPlayerDLNA::notifyPMTUpdate - Send pmtUpdate");
1890  m_playerClient->pmtUpdate();
1891  m_pmtUpdate = false;
1892  }
1893  else
1894  {
1895  LOG_INFO("MediaPlayerDLNA::notifyPMTUpdate - Send PSIReady");
1896  m_playerClient->psiReady();
1897  }
1898 }
1899 
1900 void MediaPlayerDLNA::notifyLanguageChange() {
1901  LOG_INFO("MediaPlayerDLNA::notifyLanguageChange - Send languageChange");
1902  m_playerClient->languageChange();
1903 }
1904 
1905 void MediaPlayerDLNA::onFirstVideoFrame() {
1906  /** Post CC handled only for the first time video frame received */
1907  if (m_isVOnlyOnce) {
1908 // m_playerClient->videoDecoderHandleReceived();
1909  onFrameReceived();
1910  m_isVOnlyOnce = false;
1911  }
1912 
1913  if (m_VODKeepPipelinePlaying) {
1914  if (m_isVODAsset && !m_EOSPending && !m_fetchTrickModeHeaders) {
1915  fetchHeaders();
1916  }
1917  } else {
1918  if (m_isVODAsset)
1919  fetchHeaders();
1920  }
1921 
1922  /* now as it is started playing video, the time bar must be moving. So update it.. */
1923  updateStates();
1924 }
1925 
1926 void MediaPlayerDLNA::onEISSDUpdate()
1927 {
1928  m_playerClient->eissDataReceived();
1929 }
1930 
1931 void MediaPlayerDLNA::notifyPlayerOfFirstAudioFrame() {
1932  if (m_isAOnlyOnce)
1933  LOG_INFO("Received First Audio Sample for the playback of URL=%s with play "
1934  "speed = %f time position = %f",
1935  m_url.c_str(),
1936  m_playbackRate,
1937  m_currentPosition);
1938  else
1939  LOG_INFO("Received First Audio Sample for the trickmode in URL=%s with play "
1940  "speed = %f time position = %f",
1941  m_url.c_str(),
1942  m_playbackRate,
1943  m_currentPosition);
1944 
1945  /* As the video being rendered is what matters, the possition query must be allowed after Video frame; But only for AV channels. For Music only, just set to true */
1946  if (m_isMusicOnlyAsset)
1947  m_allowPositionQueries = true; // Allow pipeline position queries now.
1948 
1949  if (m_onFirstAudioFrameHandler)
1950  g_source_remove(m_onFirstAudioFrameHandler);
1951  m_onFirstAudioFrameHandler = g_timeout_add(0, [](gpointer data) -> gboolean {
1952  MediaPlayerDLNA& self = *static_cast<MediaPlayerDLNA*>(data);
1953  self.m_onFirstAudioFrameHandler = 0;
1954  self.onFirstAudioFrame();
1955  return G_SOURCE_REMOVE;
1956  }, this);
1957 }
1958 
1959 void MediaPlayerDLNA::onFirstAudioFrame() {
1960  if (m_isAOnlyOnce) {
1961  onFrameReceived();
1962  m_isAOnlyOnce = false;
1963  }
1964 }
1965 
1966 void MediaPlayerDLNA::onFrameReceived() {
1967  // Report First Frame received only once in the beginning
1968  if (m_isVOnlyOnce && m_isAOnlyOnce)
1969  {
1970  /** Post CC handle only for the first frame received */
1971  m_playerClient->videoDecoderHandleReceived();
1972  m_playerClient->mediaFrameReceived();
1973  }
1974 }
1975 
1976 void MediaPlayerDLNA::notifyPlayerOfMediaWarning() {
1977  if (m_onMediaWarningReceivedHandler)
1978  g_source_remove(m_onMediaWarningReceivedHandler);
1979  m_onMediaWarningReceivedHandler = g_timeout_add(0, [](gpointer data) -> gboolean {
1980  MediaPlayerDLNA& self = *static_cast<MediaPlayerDLNA*>(data);
1981  self.m_onMediaWarningReceivedHandler = 0;
1982  self.onMediaWarningReceived();
1983  return G_SOURCE_REMOVE;
1984  }, this);
1985 }
1986 
1987 void MediaPlayerDLNA::onMediaWarningReceived() {
1988  if (m_sink) {
1989  m_rmfMediaWarnDesc = m_sink->getMediaWarningString();
1990  m_rmfMediaWarnData = m_sink->getMediaBufferSize();
1991  m_playerClient->mediaWarningReceived();
1992  }
1993 }
1994 
1995 void MediaPlayerDLNA::onPlay() {
1996  LOG_INFO("DLNA player: on play");
1997  m_isEndReached = false;
1998 
1999  // Adjust the video window to the same size once again..
2000  // There are platforms which is taking the rectangle param only at playing
2001  // state..
2002  m_sink->setVideoRectangle(m_lastKnownRect.x(),
2003  m_lastKnownRect.y(),
2004  m_lastKnownRect.width(),
2005  m_lastKnownRect.height(),
2006  true);
2007 
2008  // make sure that the AV is muted on the blocked content
2009  if (m_muted)
2010  m_sink->setMuted(true);
2011 
2012  /* Update the time when first frame is received */
2013  m_currentPosition = rmf_getCurrentTime();
2014 
2015  updateStates();
2016 }
2017 
2018 void MediaPlayerDLNA::onPause() {
2019  LOG_INFO("DLNA player: on pause");
2020  updateStates();
2021 }
2022 
2023 void MediaPlayerDLNA::onStop() {
2024  LOG_INFO("DLNA player: on stop");
2025  updateStates();
2026 }
2027 
2028 void MediaPlayerDLNA::rmf_setVolume(float volume) {
2029  if (!m_sink)
2030  return;
2031 
2032  m_sink->setVolume(volume);
2033 }
2034 
2035 float MediaPlayerDLNA::rmf_getVolume() const {
2036  if (!m_sink)
2037  return 0.0;
2038 
2039  return m_sink->getVolume();
2040 }
2041 
2042 void MediaPlayerDLNA::rmf_setRate(float rate) {
2043  LOG_INFO(
2044  "setRate called new speed=%f previous speed=%f pos=%f",
2045  rate,
2046  rmf_getRate(),
2047  playbackPosition());
2048  rmf_changeSpeed(rate, 0.0f);
2049 }
2050 
2051 void MediaPlayerDLNA::rmf_changeSpeed(float rate, short overShootTime) {
2052  LOG_INFO("changeSpeed called new speed=%f previous speed=%f pos=%f, overShootTime=%d", rate,
2053  rmf_getRate(), playbackPosition(), overShootTime);
2054  if (!m_source) {
2055  LOG_INFO("No source, skip changeSpeed.");
2056  return;
2057  }
2058 #ifdef ENABLE_DIRECT_QAM
2059  /* Trick mode is allowed only for VOD and mDVR */
2060  if (!(m_isDVRAsset | m_isVODAsset))
2061  return;
2062 #endif /* ENABLE_DIRECT_QAM */
2063  if (m_playbackRate == rate)
2064  return;
2065 
2066  m_pausedInternal = true;
2067 
2068  {
2069  m_currentPosition = rmf_getCurrentTime();
2070  m_currentPosition += overShootTime;
2071 
2072  if (m_currentPosition < 0)
2073  m_currentPosition = 0;
2074 
2075  double position = m_currentPosition;
2076 
2077  if (m_isVODAsset) {
2078  if (!m_VODKeepPipelinePlaying) {
2079  m_allowPositionQueries = false; // Will ensure that redundant position requests are avoided
2080  }
2081  /* DO NOT Update the m_playbackRate before getting the HEAD Response from RMFStreamer. */
2082  if (m_VODKeepPipelinePlaying) {
2083  if (m_EOSPending) {
2084  LOG_INFO("Rate Change is not accepted as VOD Server posted that it is sending EOS shortly");
2085  return;
2086  }
2087  if (!m_isAOnlyOnce) {
2088  fetchHeadersForTrickMode(rate, position);
2089  m_pausedInternal = false;
2090  if (rate != 1.0)
2091  m_isVODRateChangeRequested = true;
2092  else
2093  m_isVODRateChangeRequested = false;
2094  }
2095  } else {
2096  m_paused = false;
2097  m_playbackRate = rate;
2098  m_currentProgressTime = 0;
2099  m_baseSeekTime = m_currentPosition;
2100 #ifndef USE_VODSRC
2101  if (m_progressTimer.isActive())
2102  m_progressTimer.stop();
2103 #endif /* USE_VODSRC */
2104  }
2105 #ifdef USE_VODSRC
2106  m_source->setSpeed (rate);
2107  m_source->setMediaTime((m_baseSeekTime * 1000));
2108 
2109  double npt = 0.00;
2110  m_source->getMediaTime(npt);
2111  m_baseSeekTime = (long long) npt/1000;
2112  m_pausedInternal = false;
2113 #else
2114  if (m_source->play (rate, position) == RMF_RESULT_SUCCESS)
2115  m_playerClient->rateChanged();
2116 #endif /* USE_VODSRC */
2117  } else {
2118  m_paused = false;
2119  m_playbackRate = rate;
2120  m_allowPositionQueries = false; // Will ensure that redundant position requests are avoided
2121  if (m_source->play (rate, position) == RMF_RESULT_SUCCESS)
2122  m_playerClient->rateChanged();
2123  else
2124  LOG_ERROR("Requested rate change(%f) is failed...", m_playbackRate);
2125  m_playerClient->timeChanged();
2126  }
2127  }
2128 }
2129 
2130 MediaPlayer::RMFPlayerState MediaPlayerDLNA::rmf_playerState () const {
2131  return m_playerState;
2132 }
2133 
2134 MediaPlayer::RMFVideoBufferState MediaPlayerDLNA::rmf_videoState() const {
2135  return m_videoState;
2136 }
2137 
2138 float MediaPlayerDLNA::maxTimeLoaded() const {
2139  if (m_errorOccured)
2140  return 0.0f;
2141 
2142  return rmf_getDuration();
2143 }
2144 
2145 void MediaPlayerDLNA::cancelLoad() {
2146  if (m_playerState < MediaPlayer::RMF_PLAYER_LOADING ||
2147  m_playerState == MediaPlayer::RMF_PLAYER_LOADED)
2148  return;
2149 
2150  rmf_stop();
2151 }
2152 
2153 void MediaPlayerDLNA::updateStates() {
2154  if (!m_source)
2155  return;
2156 
2157  if (m_errorOccured) {
2158  LOG_INFO("Error occured");
2159  return;
2160  }
2161 
2162  MediaPlayer::RMFPlayerState oldNetworkState = m_playerState;
2163  MediaPlayer::RMFVideoBufferState oldReadyState = m_videoState;
2164  RMFState state;
2165  RMFState pending;
2166 
2167  RMFStateChangeReturn ret = m_source->getState(&state, &pending);
2168  LOG_VERBOSE("updateStates(): state: %s, pending: %s, ret = %s",
2169  gst_element_state_get_name((GstState) state),
2170  gst_element_state_get_name((GstState) pending),
2171  gst_element_state_change_return_get_name((GstStateChangeReturn) ret));
2172 
2173  bool shouldUpdateAfterSeek = false;
2174  switch (ret) {
2175  case RMF_STATE_CHANGE_SUCCESS:
2176  LOG_VERBOSE("State: %s, pending: %s",
2177  gst_element_state_get_name((GstState) state),
2178  gst_element_state_get_name((GstState) pending));
2179 
2180  // Try to figure out ready and network states.
2181  if (state == RMF_STATE_READY) {
2182  m_videoState = MediaPlayer::RMF_VIDEO_BUFFER_HAVEMETADATA;
2183  m_playerState = MediaPlayer::RMF_PLAYER_EMPTY;
2184  // Cache the duration without emiting the durationchange
2185  // event because it's taken care of by the media element
2186  // in this precise case.
2187  cacheDuration();
2188 #ifdef ENABLE_DIRECT_QAM
2189  /* The QAMSrc and all its child class will post no-prerolling.
2190  * But when exit from mDVR, it will find the tuner tuned that freq already and try to reuse it.
2191  * Thus we will get only this event arrive until we call play(). But play will not be
2192  * invoked by WebKit until we report we have EnoughData.
2193  */
2194  if (!m_isDVRAsset)
2195  m_videoState = MediaPlayer::RMF_VIDEO_BUFFER_HAVEENOUGHDATA;
2196 #endif /* ENABLE_DIRECT_QAM */
2197  } else if (maxTimeLoaded() == rmf_getDuration()) {
2198  m_playerState = MediaPlayer::RMF_PLAYER_LOADED;
2199  m_videoState = MediaPlayer::RMF_VIDEO_BUFFER_HAVEENOUGHDATA;
2200  } else {
2201  m_videoState = rmf_getCurrentTime() < maxTimeLoaded() ? MediaPlayer::RMF_VIDEO_BUFFER_HAVEFUTUREDATA : MediaPlayer::RMF_VIDEO_BUFFER_HAVECURRENTDATA;
2202  m_playerState = MediaPlayer::RMF_PLAYER_LOADING;
2203  }
2204  // Now let's try to get the states in more detail using
2205  // information from GStreamer, while we sync states where
2206  // needed.
2207  if (state == RMF_STATE_PAUSED) {
2208  if (rmf_getCurrentTime() < rmf_getDuration()) {
2209  m_pausedInternal = true;
2210  m_videoState = MediaPlayer::RMF_VIDEO_BUFFER_HAVECURRENTDATA;
2211  m_playerState = MediaPlayer::RMF_PLAYER_LOADING;
2212  m_playerClient->timeChanged();
2213  }
2214  } else if (state == RMF_STATE_PLAYING) {
2215  m_videoState = MediaPlayer::RMF_VIDEO_BUFFER_HAVEENOUGHDATA;
2216  m_playerState = MediaPlayer::RMF_PLAYER_LOADED;
2217  m_pausedInternal = false;
2218 
2219  m_seeking = false;
2220  m_playerClient->timeChanged();
2221  } else {
2222  m_pausedInternal = true;
2223  }
2224 
2225  if (rmf_isSeeking()) {
2226  shouldUpdateAfterSeek = true;
2227  m_seeking = false;
2228  }
2229 
2230  break;
2231  case RMF_STATE_CHANGE_ASYNC:
2232  LOG_VERBOSE("Async: State: %s, pending: %s",
2233  gst_element_state_get_name((GstState)state),
2234  gst_element_state_get_name((GstState)pending));
2235  // Change in progress
2236 
2237  if (!m_isStreaming)
2238  return;
2239 
2240  if (rmf_isSeeking()) {
2241  shouldUpdateAfterSeek = true;
2242  m_seeking = false;
2243  }
2244  break;
2245  case RMF_STATE_CHANGE_FAILURE:
2246  LOG_VERBOSE("Failure: State: %s, pending: %s",
2247  gst_element_state_get_name((GstState)state),
2248  gst_element_state_get_name((GstState)pending));
2249  // Change failed
2250  return;
2251  case RMF_STATE_CHANGE_NO_PREROLL:
2252  LOG_VERBOSE("No preroll: State: %s, pending: %s",
2253  gst_element_state_get_name((GstState)state),
2254  gst_element_state_get_name((GstState)pending));
2255 
2256  if (state == RMF_STATE_READY) {
2257  m_videoState = MediaPlayer::RMF_VIDEO_BUFFER_HAVENOTHING;
2258  } else if (state == RMF_STATE_PAUSED) {
2259  m_videoState = MediaPlayer::RMF_VIDEO_BUFFER_HAVEENOUGHDATA;
2260  m_pausedInternal = true;
2261  // Live pipelines go in PAUSED without prerolling.
2262  m_isStreaming = true;
2263  } else if (state == RMF_STATE_PLAYING) {
2264  m_pausedInternal = false;
2265  }
2266 
2267  if (rmf_isSeeking()) {
2268  shouldUpdateAfterSeek = true;
2269  m_seeking = false;
2270  if (!m_pausedInternal)
2271  m_source->play();
2272  } else if (!m_pausedInternal) {
2273  m_source->play();
2274  }
2275 
2276  m_playerState = MediaPlayer::RMF_PLAYER_LOADING;
2277  break;
2278  default:
2279  LOG_VERBOSE("Else : %d", ret);
2280  break;
2281  }
2282 
2283  if (rmf_isSeeking())
2284  m_videoState = MediaPlayer::RMF_VIDEO_BUFFER_HAVENOTHING;
2285 
2286  if (shouldUpdateAfterSeek)
2287  m_playerClient->timeChanged();
2288 
2289  if (m_playerState != oldNetworkState) {
2290  LOG_INFO("Network State Changed from %u to %u",
2291  oldNetworkState, m_playerState);
2292  m_playerClient->playerStateChanged();
2293  }
2294  if (m_videoState != oldReadyState) {
2295  LOG_INFO("Ready State Changed from %u to %u",
2296  oldReadyState, m_videoState);
2297  m_playerClient->videoStateChanged();
2298  }
2299 
2300  if (!m_progressTimer.isActive() && !rmf_isSeeking() && !m_paused)
2301  m_progressTimer.startOneShot(0);
2302 }
2303 
2304 void MediaPlayerDLNA::timeChanged() {
2305  updateStates();
2306  m_playerClient->timeChanged();
2307 }
2308 
2309 void MediaPlayerDLNA::ended() {
2310  if (m_progressTimer.isActive())
2311  m_progressTimer.stop();
2312 
2313  m_isEndReached = true;
2314 
2315  if (m_playbackRate < 0)
2316  {
2317  LOG_INFO("MediaPlayerDLNA: We have hit starting point when rewinding; Start from beginning\n");
2318  m_playbackRate = 1.0f;
2319  m_playerClient->rateChanged();
2320  rmf_seekToStartPosition();
2321  return;
2322  }
2323  else if (m_isInProgressRecording && (m_playbackRate >= 1))
2324  {
2325  LOG_INFO("MediaPlayerDLNA: We have got EOS for the asset and lets switch to Live/LivePoint\n");
2326  m_playbackRate = 1.0f;
2327  m_playerClient->rateChanged();
2328  rmf_seekToLivePosition();
2329  return;
2330  }
2331 
2332  // EOS was reached but in case of reverse playback the position is
2333  // not always 0. So to not confuse the HTMLMediaElement we
2334  // synchronize position and duration values.
2335  float now = rmf_getCurrentTime();
2336  if (now > 0) {
2337  m_mediaDuration = now;
2338  m_mediaDurationKnown = true;
2339  m_playerClient->durationChanged();
2340  }
2341  m_playerClient->timeChanged();
2342  m_playerClient->mediaPlaybackCompleted();
2343 }
2344 
2345 void MediaPlayerDLNA::cacheDuration() {
2346  if (0 == m_mediaDuration)
2347  m_mediaDuration = rmf_getCurrentTime();
2348 
2349  m_mediaDurationKnown = !std::isinf(m_mediaDuration);
2350 }
2351 
2352 void MediaPlayerDLNA::durationChanged() {
2353  float previousDuration = m_mediaDuration;
2354 
2355  cacheDuration();
2356  // Avoid emiting durationchanged in the case where the previous
2357  // duration was 0 because that case is already handled by the
2358  // HTMLMediaElement.
2359  if (previousDuration && m_mediaDuration != previousDuration)
2360  m_playerClient->durationChanged();
2361 }
2362 
2363 void MediaPlayerDLNA::rmf_setMute(bool muted) {
2364  m_muted = muted;
2365  if (m_sink)
2366  m_sink->setMuted(muted);
2367 }
2368 
2369 void MediaPlayerDLNA::loadingFailed(MediaPlayer::RMFPlayerState error) {
2370  LOG_ERROR("error=%s", StateString(error));
2371  m_errorOccured = true;
2372  if (m_playerState != error) {
2373  m_playerState = error;
2374  m_playerClient->playerStateChanged();
2375  }
2376  if (m_videoState != MediaPlayer::RMF_VIDEO_BUFFER_HAVENOTHING) {
2377  m_videoState = MediaPlayer::RMF_VIDEO_BUFFER_HAVENOTHING;
2378  m_playerClient->videoStateChanged();
2379  }
2380 }
2381 
2382 void MediaPlayerDLNA::rmf_setVideoRectangle(
2383  unsigned x, unsigned y, unsigned w, unsigned h) {
2384  IntRect temp(x, y, w, h);
2385  if (m_lastKnownRect != temp) {
2386  m_lastKnownRect = temp;
2387  if (m_sink) {
2388  LOG_VERBOSE("setVideoRectangle: %d,%d %dx%d", x, y, w, h);
2389  m_sink->setVideoRectangle(x, y, w, h, true);
2390  }
2391  }
2392 }
2393 
2394 // static
2395 bool MediaPlayerDLNA::supportsUrl(const std::string& urlStr)
2396 {
2397  return
2398  has_substring(urlStr, "/hnStreamStart") ||
2399  has_substring(urlStr, "/vldms/") ||
2400  has_substring(urlStr, "ocap://") ||
2401  has_substring(urlStr, "tune://") ||
2402  has_substring(urlStr, "vod://") ||
2403  has_substring(urlStr, "ippv://") ||
2404  has_substring(urlStr, "profile=MPEG_TS") ||
2405  has_substring(urlStr, ".ts") ||
2406  has_substring(urlStr, ".m2ts");
2407 }
RequestInfo
Definition: mediaplayerdlna.cpp:64
MediaPlayer
Definition: mediaplayer.h:51
write_callback
static size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
write callback to be used by CURL
Definition: AampCurlStore.cpp:122
ResponseInfo
Definition: mediaplayerdlna.cpp:69
MediaPlayerClient
Definition: mediaplayer.h:29
MediaPlayerDLNA
Definition: mediaplayerdlna.h:45
LOG_INFO
#define LOG_INFO(AAMP_JS_OBJECT, FORMAT,...)
Definition: jsutils.h:39
IntRect
Definition: intrect.h:22
LOG_TRACE
#define LOG_TRACE
Definition: rdk_debug_priv.c:83