MythTV  master
HLSPlaylistWorker.cpp
Go to the documentation of this file.
1 #include "HLSPlaylistWorker.h"
2 #include "HLSReader.h"
3 
4 const int PLAYLIST_FAILURE = 20; // number of consecutive failures after which
5  // an error will be propagated.
6 
7 #define LOC QString("%1 playlist: ").arg(m_parent->StreamURL().isEmpty() ? "Worker" : m_parent->StreamURL())
8 
10  : MThread("HLSPlaylist"), m_parent(parent)
11 {
12  LOG(VB_RECORD, LOG_DEBUG, LOC + "ctor");
13 }
14 
16 {
17  LOG(VB_RECORD, LOG_DEBUG, LOC + "dtor");
18 }
19 
21 {
22  LOG(VB_RECORD, LOG_INFO, LOC + "Cancel -- begin");
23  m_lock.lock();
24  m_cancel = true;
25  m_waitcond.wakeAll();
26  m_lock.unlock();
27  wait();
28  LOG(VB_RECORD, LOG_INFO, LOC + "Cancel -- end");
29 }
30 
32 {
33  std::chrono::milliseconds wakeup = 1s;
34  double delay = 0;
35 
36  LOG(VB_RECORD, LOG_INFO, LOC + "run -- begin");
37 
38  RunProlog();
39 
40  auto *downloader = new MythSingleDownload;
41 
42  while (!m_cancel)
43  {
44  m_lock.lock();
45  if (!m_wokenup)
46  {
47  std::chrono::milliseconds waittime = std::max(1000ms, wakeup);
48  LOG(VB_RECORD, (waittime > 12s ? LOG_INFO : LOG_DEBUG), LOC +
49  QString("refreshing in %2ms")
50  .arg(waittime.count()));
51  m_waitcond.wait(&m_lock, duration_cast<std::chrono::milliseconds>(
52  waittime).count());
53  }
54  m_wokenup = false;
55  m_lock.unlock();
56 
57  if (m_parent->FatalError())
58  {
59  LOG(VB_GENERAL, LOG_CRIT, LOC + "Fatal error detected");
60  break;
61  }
62  if (m_cancel)
63  {
64  LOG(VB_RECORD, LOG_INFO, LOC + "canceled");
65  break;
66  }
67 
68  if (m_parent->LoadMetaPlaylists(*downloader))
69  {
70  if (m_parent->PlaylistRetryCount() > 0)
71  {
72  LOG(VB_RECORD, LOG_INFO, LOC +
73  QString("Playlist successfully downloaded. Buffered: %1%")
74  .arg(m_parent->PercentBuffered()));
75  }
77  delay = 0.5;
78  }
79  else
80  {
82  LOG(VB_RECORD, LOG_WARNING, LOC +
83  QString("Playlist download failed -- Retry #%1, "
84  "Buffered: %2%")
86  .arg((m_parent->PercentBuffered())));
87 
88  if (m_parent->PlaylistRetryCount() > 1)
89  {
90  // Asking QNetworkAccessManager to redownload after a
91  // failure seems to result in another failure, even if the
92  // playlist is now available. So, create a new instance.
93  delete downloader;
94  downloader = new MythSingleDownload;
95 
96  if (m_parent->PlaylistRetryCount() == 3)
98  if (m_parent->PlaylistRetryCount() < 4)
101  {
102  LOG(VB_RECORD, LOG_ERR, LOC + "Loading playlist failed. "
103  "Perform a complete reset.");
105  }
106  }
107 
108  if (m_parent->PercentBuffered() > 85)
109  {
110  // Don't wait, we need more segments to work on.
111  if (m_parent->PlaylistRetryCount() == 1)
112  continue; // restart immediately if it's the first try
113  delay = 0.5;
114  }
115  else if (m_parent->PlaylistRetryCount() == 1)
116  delay = 0.5;
117  else if (m_parent->PlaylistRetryCount() == 2)
118  delay = 1;
119  else
120  delay = 2;
121  }
122 
123  // When should the playlist be reloaded
124  wakeup = m_parent->TargetDuration() > 0s ?
125  m_parent->TargetDuration() : 10s;
126  wakeup *= delay;
127  if (wakeup > 60s)
128  wakeup = 60s;
129  }
130 
131  if (downloader)
132  {
133  downloader->Cancel();
134  delete downloader;
135  }
136 
137  RunEpilog();
138 
139  LOG(VB_RECORD, LOG_INFO, LOC + "run -- end");
140 }
HLSReader::FatalError
bool FatalError(void) const
Definition: HLSReader.h:53
HLSReader::TargetDuration
std::chrono::seconds TargetDuration(void) const
Definition: HLSReader.h:75
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:1033
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:637
HLSReader::EnableDebugging
void EnableDebugging(void)
Definition: HLSReader.cpp:1041
HLSReader::PercentBuffered
uint PercentBuffered(void) const
Definition: HLSReader.cpp:882
HLSPlaylistWorker::~HLSPlaylistWorker
~HLSPlaylistWorker(void) override
Definition: HLSPlaylistWorker.cpp:15
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:4
HLSReader::AllowPlaylistSwitch
void AllowPlaylistSwitch(void)
Definition: HLSReader.h:78
HLSReader
Definition: HLSReader.h:34
HLSReader::PlaylistRetrying
void PlaylistRetrying(void)
Definition: HLSReader.cpp:1026
MythSingleDownload
Definition: mythsingledownload.h:25
HLSPlaylistWorker::Cancel
void Cancel(void)
Definition: HLSPlaylistWorker.cpp:20
MThread
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:48
HLSPlaylistWorker::HLSPlaylistWorker
HLSPlaylistWorker(HLSReader *parent)
Definition: HLSPlaylistWorker.cpp:9
HLSReader::ResetStream
void ResetStream(void)
Definition: HLSReader.h:56
LOC
#define LOC
Definition: HLSPlaylistWorker.cpp:7
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:31
HLSReader::PlaylistGood
void PlaylistGood(void)
Definition: HLSReader.cpp:1019
HLSPlaylistWorker::m_lock
QMutex m_lock
Definition: HLSPlaylistWorker.h:29
HLSReader.h