MythTV  master
HLSPlaylistWorker.cpp
Go to the documentation of this file.
1 #include "HLSPlaylistWorker.h"
2 
4 
5 #include "HLSReader.h"
6 
7 const int PLAYLIST_FAILURE = 20; // number of consecutive failures after which
8  // an error will be propagated.
9 
10 #define LOC QString("%1 playlist: ").arg(m_parent->StreamURL().isEmpty() ? "Worker" : m_parent->StreamURL())
11 
13  : MThread("HLSPlaylist"), m_parent(parent)
14 {
15  LOG(VB_RECORD, LOG_DEBUG, LOC + "ctor");
16 }
17 
19 {
20  LOG(VB_RECORD, LOG_DEBUG, LOC + "dtor");
21 }
22 
24 {
25  LOG(VB_RECORD, LOG_INFO, LOC + "Cancel -- begin");
26  m_lock.lock();
27  m_cancel = true;
28  m_waitcond.wakeAll();
29  m_lock.unlock();
30  wait();
31  LOG(VB_RECORD, LOG_INFO, LOC + "Cancel -- end");
32 }
33 
35 {
36  std::chrono::milliseconds wakeup = 1s;
37  double delay = 0;
38 
39  LOG(VB_RECORD, LOG_INFO, LOC + "run -- begin");
40 
41  RunProlog();
42 
43  auto *downloader = new MythSingleDownload;
44  m_wokenup = true; // Otherwise always false and then we start with 1 second delay
45  while (!m_cancel)
46  {
47  m_lock.lock();
48  if (!m_wokenup)
49  {
50  std::chrono::milliseconds waittime = std::max(1000ms, wakeup);
51  LOG(VB_RECORD, (waittime > 12s ? LOG_INFO : LOG_DEBUG), LOC +
52  QString("refreshing in %2ms")
53  .arg(waittime.count()));
54  m_waitcond.wait(&m_lock, duration_cast<std::chrono::milliseconds>(
55  waittime).count());
56  }
57  m_wokenup = false;
58  m_lock.unlock();
59 
60  if (m_parent->FatalError())
61  {
62  LOG(VB_GENERAL, LOG_CRIT, LOC + "Fatal error detected");
63  break;
64  }
65  if (m_cancel)
66  {
67  LOG(VB_RECORD, LOG_INFO, LOC + "canceled");
68  break;
69  }
70 
71  if (m_parent->LoadMetaPlaylists(*downloader))
72  {
73  if (m_parent->PlaylistRetryCount() > 0)
74  {
75  LOG(VB_RECORD, LOG_INFO, LOC +
76  QString("Playlist successfully downloaded. Buffered: %1%")
77  .arg(m_parent->PercentBuffered()));
78  }
80  delay = 0.5;
81  }
82  else
83  {
85  LOG(VB_RECORD, LOG_WARNING, LOC +
86  QString("Playlist download failed -- Retry #%1, "
87  "Buffered: %2%")
89  .arg((m_parent->PercentBuffered())));
90 
91  if (m_parent->PlaylistRetryCount() > 1)
92  {
93  // Asking QNetworkAccessManager to redownload after a
94  // failure seems to result in another failure, even if the
95  // playlist is now available. So, create a new instance.
96  delete downloader;
97  downloader = new MythSingleDownload;
98 
99  if (m_parent->PlaylistRetryCount() == 3)
101  if (m_parent->PlaylistRetryCount() < 4)
104  {
105  LOG(VB_RECORD, LOG_ERR, LOC + "Loading playlist failed. "
106  "Perform a complete reset.");
108  }
109  }
110 
111  if (m_parent->PercentBuffered() > 85)
112  {
113  // Don't wait, we need more segments to work on.
114  if (m_parent->PlaylistRetryCount() == 1)
115  continue; // restart immediately if it's the first try
116  delay = 0.5;
117  }
118  else if (m_parent->PlaylistRetryCount() == 1)
119  {
120  delay = 0.5;
121  }
122  else if (m_parent->PlaylistRetryCount() == 2)
123  {
124  delay = 1;
125  }
126  else
127  {
128  delay = 2;
129  }
130  }
131 
132  // When should the playlist be reloaded
133  wakeup = m_parent->TargetDuration() > 0s ?
134  m_parent->TargetDuration() : 10s;
135 
136  wakeup = std::chrono::milliseconds(static_cast<int>(delay * wakeup.count()));
137 
138  if (wakeup > 60s)
139  wakeup = 60s;
140 
141  LOG(VB_RECORD, LOG_DEBUG, LOC +
142  QString(" TargetDuration:%1s").arg(m_parent->TargetDuration().count()) +
143  QString(" wakeup:%1ms delay:%2").arg(wakeup.count()).arg(delay));
144  }
145 
146  if (downloader)
147  {
148  downloader->Cancel();
149  delete downloader;
150  }
151 
152  RunEpilog();
153 
154  LOG(VB_RECORD, LOG_INFO, LOC + "run -- end");
155 }
HLSReader::FatalError
bool FatalError(void) const
Definition: HLSReader.h:52
HLSReader::TargetDuration
std::chrono::seconds TargetDuration(void) const
Definition: HLSReader.h:74
MThread::wait
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:300
HLSPlaylistWorker::m_parent
HLSReader * m_parent
Definition: HLSPlaylistWorker.h:24
HLSPlaylistWorker.h
HLSReader::PlaylistRetryCount
int PlaylistRetryCount(void) const
Definition: HLSReader.cpp:1153
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MThread::RunProlog
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:196
HLSPlaylistWorker::m_waitcond
QWaitCondition m_waitcond
Definition: HLSPlaylistWorker.h:28
HLSPlaylistWorker::m_wokenup
bool m_wokenup
Definition: HLSPlaylistWorker.h:26
HLSReader::LoadMetaPlaylists
bool LoadMetaPlaylists(MythSingleDownload &downloader)
Definition: HLSReader.cpp:737
mythlogging.h
HLSReader::EnableDebugging
void EnableDebugging(void)
Definition: HLSReader.cpp:1161
HLSReader::PercentBuffered
uint PercentBuffered(void) const
Definition: HLSReader.cpp:986
HLSPlaylistWorker::~HLSPlaylistWorker
~HLSPlaylistWorker(void) override
Definition: HLSPlaylistWorker.cpp:18
MThread::RunEpilog
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:209
HLSPlaylistWorker::m_cancel
bool m_cancel
Definition: HLSPlaylistWorker.h:25
PLAYLIST_FAILURE
const int PLAYLIST_FAILURE
Definition: HLSPlaylistWorker.cpp:7
HLSReader::AllowPlaylistSwitch
void AllowPlaylistSwitch(void)
Definition: HLSReader.h:77
HLSReader
Definition: HLSReader.h:33
HLSReader::PlaylistRetrying
void PlaylistRetrying(void)
Definition: HLSReader.cpp:1146
MythSingleDownload
Definition: mythsingledownload.h:25
HLSPlaylistWorker::Cancel
void Cancel(void)
Definition: HLSPlaylistWorker.cpp:23
MThread
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:48
HLSPlaylistWorker::HLSPlaylistWorker
HLSPlaylistWorker(HLSReader *parent)
Definition: HLSPlaylistWorker.cpp:12
HLSReader::ResetStream
void ResetStream(void)
Definition: HLSReader.h:55
LOC
#define LOC
Definition: HLSPlaylistWorker.cpp:10
HLSPlaylistWorker::run
void run() override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: HLSPlaylistWorker.cpp:34
HLSReader::PlaylistGood
void PlaylistGood(void)
Definition: HLSReader.cpp:1139
HLSPlaylistWorker::m_lock
QMutex m_lock
Definition: HLSPlaylistWorker.h:29
HLSReader.h