MythTV master
vboxchannelfetcher.cpp
Go to the documentation of this file.
1// Std C headers
2#include <cmath>
3#include <unistd.h>
4#include <utility>
5
6// Qt headers
7#include <QFile>
8#include <QTextStream>
9
10// MythTV headers
13#include "cardutil.h"
14#include "channelutil.h"
15#include "recorders/vboxutils.h"
16#include "scanmonitor.h"
17#include "vboxchannelfetcher.h"
18
19#define LOC QString("VBoxChanFetch: ")
20
21VBoxChannelFetcher::VBoxChannelFetcher(uint cardid, QString inputname, uint sourceid,
22 bool ftaOnly, ServiceRequirements serviceType,
23 ScanMonitor *monitor) :
24 m_scanMonitor(monitor),
25 m_cardId(cardid), m_inputName(std::move(inputname)),
26 m_sourceId(sourceid), m_ftaOnly(ftaOnly),
27 m_serviceType(serviceType),
28 m_thread(new MThread("VBoxChannelFetcher", this))
29{
30 LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Has ScanMonitor %1")
31 .arg(monitor?"true":"false"));
32
33 // videoDev is of the form xx.xx.xx.xx-n-t or xxxxxxx-n-t
34 QString videoDev = CardUtil::GetVideoDevice(cardid);
35 QStringList list = videoDev.split('-');
36 if (list.count() == 3)
37 {
38 const QString& tunerType = list.at(2);
39 if (tunerType == "DVBT")
40 m_transType = "T";
41 else if (tunerType == "DVBT/T2")
42 m_transType = "T2";
43 else if (tunerType == "DVBS")
44 m_transType = "S";
45 else if (tunerType == "DVBS/S2")
46 m_transType = "S2";
47 else if (tunerType == "DVBC")
48 m_transType = "C";
49 else if (tunerType == "ATSC")
50 m_transType = "A";
51 }
52
53 LOG(VB_CHANNEL, LOG_INFO, LOC + QString("VideoDevice is: %1, tunerType is: %2")
54 .arg(videoDev, m_transType));
55}
56
58{
59 Stop();
60 delete m_thread;
61 m_thread = nullptr;
62 delete m_channels;
63 m_channels = nullptr;
64}
65
70{
71 m_lock.lock();
72
73 while (m_threadRunning)
74 {
75 m_stopNow = true;
76 m_lock.unlock();
77 m_thread->wait(5ms);
78 m_lock.lock();
79 }
80
81 m_lock.unlock();
82
83 m_thread->wait();
84}
85
87{
88 while (!m_thread->isFinished())
89 m_thread->wait(500ms);
90
91 LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Found %1 channels")
92 .arg(m_channels->size()));
93 return *m_channels;
94}
95
97{
98 Stop();
99 m_stopNow = false;
100 m_thread->start();
101}
102
104{
105 m_lock.lock();
106 m_threadRunning = true;
107 m_lock.unlock();
108
109 // Step 1/3 : Get the IP of the VBox to query
110 QString dev = CardUtil::GetVideoDevice(m_cardId);
111 QString ip = VBox::getIPFromVideoDevice(dev);
112
113 if (m_stopNow || ip.isEmpty())
114 {
115 LOG(VB_CHANNEL, LOG_INFO, LOC +
116 QString("Failed to get IP address from videodev (%1)").arg(dev));
117 QMutexLocker locker(&m_lock);
118 m_threadRunning = false;
119 m_stopNow = true;
120 return;
121 }
122
123 LOG(VB_CHANNEL, LOG_INFO, LOC + QString("VBox IP: %1").arg(ip));
124
125 // Step 2/3 : Download
126 if (m_scanMonitor)
127 {
129 m_scanMonitor->ScanAppendTextToLog(tr("Downloading Channel List"));
130 }
131
132 delete m_channels;
133
134 VBox *vbox = new VBox(ip);
135 m_channels = vbox->getChannels();
136 delete vbox;
137
138 if (m_stopNow || !m_channels)
139 {
141 {
142 m_scanMonitor->ScanAppendTextToLog(QCoreApplication::translate("(Common)", "Error"));
144 m_scanMonitor->ScanErrored(tr("Downloading Channel List Failed"));
145 }
146 QMutexLocker locker(&m_lock);
147 m_threadRunning = false;
148 m_stopNow = true;
149 return;
150 }
151
152 // Step 3/3 : Process
153 if (m_scanMonitor)
154 {
156 m_scanMonitor->ScanAppendTextToLog(tr("Adding Channels"));
157 }
158
160
161 LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Found %1 channels")
162 .arg(m_channels->size()));
163
164 // add the channels to the DB
165 vbox_chan_map_t::const_iterator it = m_channels->cbegin();
166 for (uint i = 1; it != m_channels->cend(); ++it, ++i)
167 {
168 const QString& channum = it.key();
169 QString name = (*it).m_name;
170 QString xmltvid = (*it).m_xmltvid.isEmpty() ? "" : (*it).m_xmltvid;
171 uint serviceID = (*it).m_serviceID;
172 bool fta = (*it).m_fta;
173 QString chanType = (*it).m_channelType;
174 QString transType = (*it).m_transType;
175 uint networkID = (*it).m_networkID;
176 uint transportID = (*it).m_transportID;
177
178 //: %1 is the channel number, %2 is the channel name
179 QString msg = tr("Channel #%1 : %2").arg(channum, name);
180
181 LOG(VB_CHANNEL, LOG_INFO, QString("Handling channel %1 %2")
182 .arg(channum, name));
183 uint mplexID = 0;
184 if (m_ftaOnly && !fta)
185 {
186 // ignore this encrypted channel
187 if (m_scanMonitor)
188 {
189 m_scanMonitor->ScanAppendTextToLog(tr("Ignoring Encrypted %1")
190 .arg(msg));
191 }
192 }
193 else if (chanType == "Radio" && m_serviceType != kRequireAudio)
194 {
195 // ignore this radio channel
196 if (m_scanMonitor)
197 {
198 m_scanMonitor->ScanAppendTextToLog(tr("Ignoring Radio %1")
199 .arg(msg));
200 }
201 }
202 else if (!SupportedTransmission(transType))
203 {
204 // ignore this channel
205 if (m_scanMonitor)
206 {
207 m_scanMonitor->ScanAppendTextToLog(tr("Ignoring Bad Transmission Type %1").arg(msg));
208 }
209 }
210 else
211 {
212 int chanid = ChannelUtil::GetChanID(m_sourceId, channum);
213
214 if (chanid <= 0)
215 {
216 if (m_scanMonitor)
217 {
218 m_scanMonitor->ScanAppendTextToLog(tr("Adding %1").arg(msg));
219 }
220 chanid = ChannelUtil::CreateChanID(m_sourceId, channum);
221
222 // mplexID will be created if necessary
223 // inversion, bandwidth, transmission_mode, polarity, hierarchy, mod_sys and roll_off are given values, but not used
224 // this is to ensure services API Channel/GetVideoMultiplexList returns a valid list
225 mplexID = ChannelUtil::CreateMultiplex(m_sourceId, "dvb", 0, QString(), transportID, networkID, 0,
226 'a', 'v', 'a', 'a', QString(), QString(), 'a', QString(),
227 QString(), QString(), "UNDEFINED", "0.35");
228
229 ChannelUtil::CreateChannel(mplexID, m_sourceId, chanid, name, name,
230 channum, serviceID, 0, 0,
231 false, kChannelVisible, QString(),
232 QString(), "Default", xmltvid);
233
234 ChannelUtil::CreateIPTVTuningData(chanid, (*it).m_tuning);
235 }
236 else
237 {
238 if (m_scanMonitor)
239 {
240 m_scanMonitor->ScanAppendTextToLog(tr("Updating %1").arg(msg));
241 }
242
243 // mplexID will be created if necessary
244 mplexID = ChannelUtil::CreateMultiplex(m_sourceId, "dvb", 0, QString(), transportID, networkID, 0,
245 'a', 'v', 'a', 'a', QString(), QString(), 'a', QString(),
246 QString(), QString(), "UNDEFINED", "0.35");
247
248 // xmltvid parameter is set to null, user may have changed it, so do not overwrite as we are only updating
249 ChannelUtil::UpdateChannel(mplexID, m_sourceId, chanid, name, name,
250 channum, serviceID, 0, 0,
251 false, kChannelVisible, QString(),
252 QString(), "Default", QString());
253
254 ChannelUtil::UpdateIPTVTuningData(chanid, (*it).m_tuning);
255 }
256 }
257
259 }
260
261 if (m_scanMonitor)
262 {
267 }
268
269 QMutexLocker locker(&m_lock);
270 m_threadRunning = false;
271 m_stopNow = true;
272}
273
275{
276 uint minval = 70;
277 uint range = 100 - minval;
278 uint pct = minval + (uint) truncf((((float)val) / m_chanCnt) * range);
279 if (m_scanMonitor)
281}
282
283bool VBoxChannelFetcher::SupportedTransmission(const QString& transType)
284{
285 if (transType == "UNKNOWN")
286 return true;
287
288 // both S and S2 tuners can tune an S channel
289 if (transType == "S" && (m_transType == "S" || m_transType == "S2"))
290 return true;
291
292 // both T and T2 tuners can tune a T channel
293 if (transType == "T" && (m_transType == "T" || m_transType == "T2"))
294 return true;
295
296 // for S2, T2, A and C the channel and tuner transmission types must match
297 return transType == m_transType;
298}
@ kChannelVisible
Definition: channelinfo.h:23
ServiceRequirements
@ kRequireAudio
static QString GetVideoDevice(uint inputid)
Definition: cardutil.h:294
static int GetChanID(int db_mplexid, int service_transport_id, int major_channel, int minor_channel, int program_number)
static bool CreateIPTVTuningData(uint channel_id, const IPTVTuningData &tuning)
Definition: channelutil.h:155
static bool UpdateIPTVTuningData(uint channel_id, const IPTVTuningData &tuning)
static bool UpdateChannel(uint db_mplexid, uint source_id, uint channel_id, const QString &callsign, const QString &service_name, const QString &chan_num, uint service_id, uint atsc_major_channel, uint atsc_minor_channel, bool use_on_air_guide, ChannelVisibleType visible, const QString &freqid=QString(), const QString &icon=QString(), QString format=QString(), const QString &xmltvid=QString(), const QString &default_authority=QString(), uint service_type=0, int recpriority=INT_MIN, int tmOffset=INT_MIN, int commMethod=INT_MIN)
static uint CreateMultiplex(int sourceid, const QString &sistandard, uint64_t frequency, const QString &modulation, int transport_id=-1, int network_id=-1)
static int CreateChanID(uint sourceid, const QString &chan_num)
Creates a unique channel ID for database use.
static bool CreateChannel(uint db_mplexid, uint db_sourceid, uint new_channel_id, const QString &callsign, const QString &service_name, const QString &chan_num, uint service_id, uint atsc_major_channel, uint atsc_minor_channel, bool use_on_air_guide, ChannelVisibleType visible, const QString &freqid, const QString &icon=QString(), QString format="Default", const QString &xmltvid=QString(), const QString &default_authority=QString(), uint service_type=0, int recpriority=0, int tmOffset=0, int commMethod=-1)
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:49
bool isFinished(void) const
Definition: mthread.cpp:258
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:283
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:300
void ScanPercentComplete(int pct)
void ScanComplete(void)
Definition: scanmonitor.cpp:98
void ScanAppendTextToLog(const QString &status)
void ScanErrored(const QString &error)
bool SupportedTransmission(const QString &transType)
ScanMonitor * m_scanMonitor
void run(void) override
void SetTotalNumChannels(uint val)
vbox_chan_map_t GetChannels(void)
void Stop(void)
Stops the scanning thread running.
void SetNumChannelsInserted(uint val)
vbox_chan_map_t * m_channels
VBoxChannelFetcher(uint cardid, QString inputname, uint sourceid, bool ftaOnly, ServiceRequirements serviceType, ScanMonitor *monitor=nullptr)
ServiceRequirements m_serviceType
Definition: vboxutils.h:17
vbox_chan_map_t * getChannels(void)
Definition: vboxutils.cpp:296
static QString getIPFromVideoDevice(const QString &dev)
Definition: vboxutils.cpp:149
unsigned int uint
Definition: freesurround.h:24
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
STL namespace.
#define LOC
QMap< QString, VBoxChannelInfo > vbox_chan_map_t