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