MythTV master
HLSPlaylistWorker.cpp
Go to the documentation of this file.
1#include "HLSPlaylistWorker.h"
2
4
5#include "HLSReader.h"
6
7const 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 {
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
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}
#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:77
void PlaylistRetrying(void)
Definition: HLSReader.cpp:1147
void EnableDebugging(void)
Definition: HLSReader.cpp:1162
std::chrono::seconds TargetDuration(void) const
Definition: HLSReader.h:74
void ResetStream(void)
Definition: HLSReader.h:55
void PlaylistGood(void)
Definition: HLSReader.cpp:1140
uint PercentBuffered(void) const
Definition: HLSReader.cpp:987
bool FatalError(void) const
Definition: HLSReader.h:52
bool LoadMetaPlaylists(MythSingleDownload &downloader)
Definition: HLSReader.cpp:738
int PlaylistRetryCount(void) const
Definition: HLSReader.cpp:1154
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:196
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:209
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:300
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39