MythTV  master
hdhrchannelfetcher.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 #include <QString>
10 #include <QStringList>
11 #include <QDomDocument>
12 
13 #ifdef USING_HDHOMERUN
14 #include HDHOMERUN_HEADERFILE
15 #endif
16 
17 // MythTV headers
20 #include "cardutil.h"
21 #include "channelutil.h"
22 #include "libmyth/mythcontext.h"
23 #include "scanmonitor.h"
24 #include "hdhrchannelfetcher.h"
25 
26 #define LOC QString("HDHRChanFetch: ")
27 
28 namespace {
29 
30 constexpr const char* QUERY_CHANNELS
31 { "http://{IP}/lineup.xml?tuning" };
32 
33 QString getFirstText(QDomElement &element)
34 {
35  for (QDomNode dname = element.firstChild(); !dname.isNull();
36  dname = dname.nextSibling())
37  {
38  QDomText t = dname.toText();
39  if (!t.isNull())
40  return t.data();
41  }
42  return {};
43 }
44 
45 QString getStrValue(const QDomElement &element, const QString &name, int index=0)
46 {
47  QDomNodeList nodes = element.elementsByTagName(name);
48  if (!nodes.isEmpty())
49  {
50  if (index >= nodes.count())
51  index = 0;
52  QDomElement e = nodes.at(index).toElement();
53  return getFirstText(e);
54  }
55  return {};
56 }
57 
58 int getIntValue(const QDomElement &element, const QString &name, int index=0)
59 {
60  QString value = getStrValue(element, name, index);
61  return value.toInt();
62 }
63 
64 bool sendQuery(const QString& query, QDomDocument* xmlDoc)
65 {
66  QByteArray result;
67 
68  if (!GetMythDownloadManager()->download(query, &result, true))
69  return false;
70 
71  QString errorMsg;
72  int errorLine = 0;
73  int errorColumn = 0;
74 
75  if (!xmlDoc->setContent(result, false, &errorMsg, &errorLine, &errorColumn))
76  {
77  LOG(VB_GENERAL, LOG_ERR, LOC +
78  QString("Error parsing: %1\nat line: %2 column: %3 msg: %4").
79  arg(query).arg(errorLine).arg(errorColumn).arg(errorMsg));
80  return false;
81  }
82 
83  // Check for a status or error element
84  QDomNodeList statusNodes = xmlDoc->elementsByTagName("Status");
85 
86  if (!statusNodes.count())
87  statusNodes = xmlDoc->elementsByTagName("Error");
88 
89  if (statusNodes.count())
90  {
91  QDomElement elem = statusNodes.at(0).toElement();
92  if (!elem.isNull())
93  {
94  int errorCode = getIntValue(elem, "ErrorCode");
95  QString errorDesc = getStrValue(elem, "ErrorDescription");
96 
97  if (errorCode == 0 /* SUCCESS */)
98  return true;
99 
100  LOG(VB_GENERAL, LOG_ERR, LOC +
101  QString("API Error: %1 - %2, Query was: %3").arg(errorCode).arg(errorDesc, query));
102 
103  return false;
104  }
105  }
106 
107  // No error detected so assume we got a valid xml result
108  return true;
109 }
110 
111 hdhr_chan_map_t *getChannels(const QString& ip)
112 {
113  auto *result = new hdhr_chan_map_t;
114  auto *xmlDoc = new QDomDocument();
115  QString query = QUERY_CHANNELS;
116 
117  query.replace("{IP}", ip);
118 
119  if (!sendQuery(query, xmlDoc))
120  {
121  delete xmlDoc;
122  delete result;
123  return nullptr;
124  }
125 
126  QDomNodeList chanNodes = xmlDoc->elementsByTagName("Program");
127 
128  for (int x = 0; x < chanNodes.count(); x++)
129  {
130  QDomElement chanElem = chanNodes.at(x).toElement();
131  QString guideName = getStrValue(chanElem, "GuideName");
132  QString guideNumber = getStrValue(chanElem, "GuideNumber");
133  QString url = getStrValue(chanElem, "URL");
134  QString modulation = getStrValue(chanElem, "Modulation");
135  QString videoCodec = getStrValue(chanElem, "VideoCodec");
136  QString audioCodec = getStrValue(chanElem, "AudioCodec");
137  uint frequency = getStrValue(chanElem, "Frequency").toUInt();
138  uint serviceID = getStrValue(chanElem, "ProgramNumber").toUInt();
139  uint transportID = getStrValue(chanElem, "TransportStreamID").toUInt();
140  QString onid = getStrValue(chanElem, "OriginalNetworkID");
141 
142  // Fixup: Remove leading colon in network ID:
143  // <OriginalNetworkID>:8720</OriginalNetworkID>
144  // This looks a bug in the XML representation, N.B. bug not present in JSON.
145  onid.replace(":", "");
146  uint originalNetworkID = onid.toUInt();
147 
148  LOG(VB_CHANSCAN, LOG_DEBUG, LOC + QString("ONID/TID/SID %1 %2 %3")
149  .arg(originalNetworkID).arg(transportID).arg(serviceID));
150 
151  HDHRChannelInfo chanInfo(guideName, guideNumber, url, modulation, videoCodec,
152  audioCodec, frequency, serviceID, originalNetworkID, transportID);
153 
154  result->insert(guideNumber, chanInfo);
155  }
156  return result;
157 }
158 
159 QString HDHRIPv4Address([[maybe_unused]] const QString &device)
160 {
161 #ifdef USING_HDHOMERUN
162  hdhomerun_device_t *hdhr =
163  hdhomerun_device_create_from_str(device.toLatin1(), nullptr);
164  if (!hdhr)
165  return {};
166 
167  uint32_t ipv4 = hdhomerun_device_get_device_ip(hdhr);
168  hdhomerun_device_destroy(hdhr);
169 
170  if (!ipv4)
171  return {};
172 
173  return QString("%1.%2.%3.%4").arg(ipv4>>24&0xff).arg(ipv4>>16&0xff).arg(ipv4>>8&0xff).arg(ipv4&0xff);
174 #else
175  return {};
176 #endif
177 }
178 
179 // Examples of hdhrmod values: a8qam64-6875 a8qam256-6900 t8dvbt2 8vsb
180 DTVModulationSystem HDHRMod2Modsys(const QString& hdhrmod)
181 {
182  if (hdhrmod.contains("dvbt2"))
184  if (hdhrmod.contains("dvbt"))
186  if (hdhrmod.startsWith("a8qam"))
188  if (hdhrmod.contains("vsb"))
190  if (hdhrmod.contains("psk"))
193 }
194 
195 signed char HDHRMod2Bandwidth(const QString& hdhrmod)
196 {
197  if (hdhrmod.startsWith("t8") || hdhrmod.startsWith("a8"))
198  return '8';
199  if (hdhrmod.startsWith("t7") || hdhrmod.startsWith("a7"))
200  return '7';
201  if (hdhrmod.startsWith("t6") || hdhrmod.startsWith("a6"))
202  return '6';
203  return 'a';
204 }
205 
206 uint HDHRMod2SymbolRate(const QString& hdhrmod)
207 {
208  static const QRegularExpression re(R"(^(a8qam\d+-)(\d+))");
209  QRegularExpressionMatch match = re.match(hdhrmod);
210  if (match.hasMatch())
211  {
212  QString matched = match.captured(2);
213  return matched.toUInt() * 1000;
214  }
215  return 0;
216 }
217 
218 QString HDHRMod2Modulation(const QString& hdhrmod)
219 {
220  if (hdhrmod.contains("qam256"))
222  if (hdhrmod.contains("qam128"))
224  if (hdhrmod.contains("qam64"))
226  if (hdhrmod.contains("qam16"))
228  if (hdhrmod.contains("qpsk"))
230  if (hdhrmod.contains("8vsb"))
233 }
234 
235 void HDHRMajorMinorChannel(QString channum, uint &atsc_major_channel, uint &atsc_minor_channel)
236 {
237  if (channum.contains("."))
238  {
239  QChar dot;
240  QTextStream(&channum) >> atsc_major_channel >> dot >> atsc_minor_channel;
241  }
242 }
243 
244 } // namespace
245 
246 HDHRChannelFetcher::HDHRChannelFetcher(uint cardid, QString inputname, uint sourceid,
247  ServiceRequirements serviceType, ScanMonitor *monitor) :
248  m_scanMonitor(monitor),
249  m_cardId(cardid),
250  m_inputName(std::move(inputname)),
251  m_sourceId(sourceid),
252  m_serviceType(serviceType),
253  m_thread(new MThread("HDHRChannelFetcher", this))
254 {
255  LOG(VB_CHANSCAN, LOG_INFO, LOC + QString("Has ScanMonitor %1")
256  .arg(monitor?"true":"false"));
257 }
258 
260 {
261  Stop();
262  delete m_thread;
263  m_thread = nullptr;
264  delete m_channels;
265  m_channels = nullptr;
266 }
267 
272 {
273  m_lock.lock();
274 
275  while (m_threadRunning)
276  {
277  m_stopNow = true;
278  m_lock.unlock();
279  m_thread->wait(5ms);
280  m_lock.lock();
281  }
282 
283  m_lock.unlock();
284 
285  m_thread->wait();
286 }
287 
289 {
290  while (!m_thread->isFinished())
291  m_thread->wait(500ms);
292 
293  LOG(VB_CHANSCAN, LOG_INFO, LOC + QString("Found %1 channels")
294  .arg(m_channels->size()));
295  return *m_channels;
296 }
297 
299 {
300  Stop();
301  m_stopNow = false;
302  m_thread->start();
303 }
304 
306 {
307  m_lock.lock();
308  m_threadRunning = true;
309  m_lock.unlock();
310 
311  // Step 1/3 : Get the IP of the HDHomeRun to query
312  QString dev = CardUtil::GetVideoDevice(m_cardId);
313  QString ip = HDHRIPv4Address(dev);
314 
315  if (m_stopNow || ip.isEmpty())
316  {
317  LOG(VB_CHANNEL, LOG_INFO, LOC +
318  QString("Failed to get IP address from videodev (%1)").arg(dev));
319  QMutexLocker locker(&m_lock);
320  m_threadRunning = false;
321  m_stopNow = true;
322  return;
323  }
324  LOG(VB_CHANNEL, LOG_INFO, LOC + QString("HDHomeRun IP: %1").arg(ip));
325 
326  // Step 2/3 : Download
327  if (m_scanMonitor)
328  {
330  m_scanMonitor->ScanAppendTextToLog(tr("Downloading Channel List"));
331  }
332 
333  delete m_channels;
334  m_channels = getChannels(ip);
335 
336  if (m_stopNow || !m_channels)
337  {
338  if (!m_channels && m_scanMonitor)
339  {
340  m_scanMonitor->ScanAppendTextToLog(QCoreApplication::translate("(Common)", "Error"));
342  m_scanMonitor->ScanErrored(tr("Downloading Channel List Failed"));
343  }
344  QMutexLocker locker(&m_lock);
345  m_threadRunning = false;
346  m_stopNow = true;
347  return;
348  }
349 
350  // Step 3/3 : Process
351  if (m_scanMonitor)
352  {
354  m_scanMonitor->ScanAppendTextToLog(tr("Adding Channels"));
355  }
357  LOG(VB_CHANSCAN, LOG_INFO, LOC + QString("Found %1 channels").arg(m_channels->size()));
358 
359  // Add the channels to the DB
360  hdhr_chan_map_t::const_iterator it = m_channels->cbegin();
361  for (uint i = 1; it != m_channels->cend(); ++it, ++i)
362  {
363  const QString& channum = it.key();
364  QString name = (*it).m_name;
365  uint serviceID = (*it).m_serviceID;
366  QString channelType = (*it).m_channelType;
367  QString hdhrmod = (*it).m_modulation;
368  uint networkID = (*it).m_networkID;
369  uint transportID = (*it).m_transportID;
370  uint frequency = (*it).m_frequency;
371 
372  DTVModulationSystem modsys = HDHRMod2Modsys(hdhrmod);
373  QString modulation = HDHRMod2Modulation(hdhrmod);
374  uint symbolrate = HDHRMod2SymbolRate(hdhrmod);
375  signed char bandwidth = HDHRMod2Bandwidth(hdhrmod);
376  uint atsc_major_channel = 0;
377  uint atsc_minor_channel = 0;
378  HDHRMajorMinorChannel(channum, atsc_major_channel, atsc_minor_channel);
379  QString sistandard = (atsc_major_channel > 0 && atsc_minor_channel > 0) ? "atsc" : "dvb";
380 
381  bool use_on_air_guide = true;
382 
383  QString msg = tr("%1 channel %2: %3").arg(channelType).arg(channum, -5, QChar(' ')).arg(name, -15, QChar(' '));
384  LOG(VB_CHANSCAN, LOG_INFO, QString("Found %1").arg(msg));
385 
386  if ((channelType == "Radio") && (m_serviceType & kRequireVideo))
387  { // NOLINT(bugprone-branch-clone)
388  // Ignore this radio channel
389  if (m_scanMonitor)
390  {
391  m_scanMonitor->ScanAppendTextToLog(tr("Ignoring %1").arg(msg));
392  }
393  }
394  else if ((channelType == "Data") && (m_serviceType != kRequireNothing))
395  {
396  // Ignore this data channel
397  if (m_scanMonitor)
398  {
399  m_scanMonitor->ScanAppendTextToLog(tr("Ignoring %1").arg(msg));
400  }
401  }
402  else
403  {
404  // This is a TV channel or another channel type that we want
405  int chanid = ChannelUtil::GetChanID(m_sourceId, channum);
406  bool adding_channel = chanid <= 0;
407 
408  if (adding_channel)
409  chanid = ChannelUtil::CreateChanID(m_sourceId, channum);
410 
411  if (m_scanMonitor)
412  {
413  if (adding_channel)
414  {
415  m_scanMonitor->ScanAppendTextToLog(tr("Adding %1").arg(msg));
416  }
417  else
418  {
419  m_scanMonitor->ScanAppendTextToLog(tr("Updating %1").arg(msg));
420  }
421  }
422 
423  // A new dtv_multiplex entry will be created if necessary, otherwise an existing one is returned
424  uint mplexID = ChannelUtil::CreateMultiplex(m_sourceId, sistandard, frequency, modulation,
425  transportID, networkID, symbolrate, bandwidth,
426  'v', 'a', 'a', QString(), QString(), 'a', QString(),
427  QString(), QString(), modsys.toString(), "0.35");
428  if (mplexID == 0)
429  {
430  LOG(VB_GENERAL, LOG_ERR, QString("No multiplex for %1 sid:%2 freq:%3 url:%4")
431  .arg(msg).arg(serviceID, -5, 10, QChar(' ')).arg(frequency).arg((*it).m_tuning.GetDataURL().toString()));
432  continue;
433  }
434 
435  if (adding_channel)
436  {
437  ChannelUtil::CreateChannel(mplexID, m_sourceId, chanid, name, name,
438  channum, serviceID, atsc_major_channel, atsc_minor_channel,
439  use_on_air_guide, kChannelVisible, QString(),
440  QString(), "Default", QString());
441 
442  ChannelUtil::CreateIPTVTuningData(chanid, (*it).m_tuning);
443  }
444  else
445  {
446  ChannelUtil::UpdateChannel(mplexID, m_sourceId, chanid, name, name,
447  channum, serviceID, atsc_major_channel, atsc_minor_channel,
448  use_on_air_guide, kChannelVisible, QString(),
449  QString(), "Default", QString());
450 
451  ChannelUtil::UpdateIPTVTuningData(chanid, (*it).m_tuning);
452  }
453  LOG(VB_GENERAL, LOG_INFO, QString("%1 sid:%2 freq:%3 url:%4")
454  .arg(msg).arg(serviceID, -5, 10, QChar(' ')).arg(frequency).arg((*it).m_tuning.GetDataURL().toString()));
455  }
457  }
458 
459  if (m_scanMonitor)
460  {
461  m_scanMonitor->ScanAppendTextToLog(tr("Done"));
464  }
465 
466  QMutexLocker locker(&m_lock);
467  m_threadRunning = false;
468  m_stopNow = true;
469 }
470 
472 {
473  uint minval = 70;
474  uint range = 100 - minval;
475  uint pct = minval + (uint) truncf((((float)val) / m_chanCnt) * range);
476  if (m_scanMonitor)
478 }
DTVModulation::toString
QString toString() const
Definition: dtvconfparserhelpers.h:412
HDHRChannelInfo
Definition: hdhrchannelfetcher.h:23
HDHRChannelFetcher::GetChannels
hdhr_chan_map_t GetChannels(void)
Definition: hdhrchannelfetcher.cpp:288
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:283
HDHRChannelFetcher::m_cardId
uint m_cardId
Definition: hdhrchannelfetcher.h:114
HDHRChannelFetcher::m_chanCnt
uint m_chanCnt
Definition: hdhrchannelfetcher.h:119
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
HDHRChannelFetcher::m_thread
MThread * m_thread
Definition: hdhrchannelfetcher.h:122
ScanMonitor::ScanPercentComplete
void ScanPercentComplete(int pct)
Definition: scanmonitor.cpp:103
HDHRChannelFetcher::m_scanMonitor
ScanMonitor * m_scanMonitor
Definition: hdhrchannelfetcher.h:113
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
DTVModulation::kModulationQPSK
@ kModulationQPSK
Definition: dtvconfparserhelpers.h:358
DTVModulationSystem::kModulationSystem_UNDEFINED
@ kModulationSystem_UNDEFINED
Definition: dtvconfparserhelpers.h:656
HDHRChannelFetcher::HDHRChannelFetcher
HDHRChannelFetcher(uint cardid, QString inputname, uint sourceid, ServiceRequirements serviceType, ScanMonitor *monitor=nullptr)
Definition: hdhrchannelfetcher.cpp:246
ScanMonitor::ScanErrored
void ScanErrored(const QString &error)
Definition: scanmonitor.cpp:128
DTVModulation::kModulationQAM256
@ kModulationQAM256
Definition: dtvconfparserhelpers.h:363
HDHRChannelFetcher::m_threadRunning
bool m_threadRunning
Definition: hdhrchannelfetcher.h:120
DTVModulation::kModulationQAM16
@ kModulationQAM16
Definition: dtvconfparserhelpers.h:359
scanmonitor.h
HDHRChannelFetcher::m_sourceId
uint m_sourceId
Definition: hdhrchannelfetcher.h:116
ChannelUtil::GetChanID
static int GetChanID(int db_mplexid, int service_transport_id, int major_channel, int minor_channel, int program_number)
Definition: channelutil.cpp:1310
mythlogging.h
HDHRChannelFetcher::Scan
void Scan(void)
Definition: hdhrchannelfetcher.cpp:298
HDHRChannelFetcher::m_stopNow
bool m_stopNow
Definition: hdhrchannelfetcher.h:121
hardwareprofile.i18n.t
t
Definition: i18n.py:36
ChannelUtil::UpdateChannel
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)
Definition: channelutil.cpp:1571
HDHRChannelFetcher::Stop
void Stop(void)
Stops the scanning thread running.
Definition: hdhrchannelfetcher.cpp:271
DTVModulation::kModulationQAM128
@ kModulationQAM128
Definition: dtvconfparserhelpers.h:362
ChannelUtil::CreateChanID
static int CreateChanID(uint sourceid, const QString &chan_num)
Creates a unique channel ID for database use.
Definition: channelutil.cpp:1446
DTVModulation::kModulationQAMAuto
@ kModulationQAMAuto
Definition: dtvconfparserhelpers.h:364
MThread::isFinished
bool isFinished(void) const
Definition: mthread.cpp:258
kRequireVideo
@ kRequireVideo
Definition: channelscantypes.h:7
uint
unsigned int uint
Definition: compat.h:81
kRequireNothing
@ kRequireNothing
Definition: channelscantypes.h:6
ScanMonitor::ScanAppendTextToLog
void ScanAppendTextToLog(const QString &status)
Definition: scanmonitor.cpp:109
DTVModulationSystem::kModulationSystem_ATSC
@ kModulationSystem_ATSC
Definition: dtvconfparserhelpers.h:667
hdhr_chan_map_t
QMap< QString, HDHRChannelInfo > hdhr_chan_map_t
Definition: hdhrchannelfetcher.h:90
ChannelUtil::CreateChannel
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)
Definition: channelutil.cpp:1483
channelutil.h
DTVModulationSystem::toString
QString toString() const
Definition: dtvconfparserhelpers.h:719
kChannelVisible
@ kChannelVisible
Definition: channelinfo.h:23
DTVModulationSystem
Definition: dtvconfparserhelpers.h:644
cardutil.h
ScanMonitor::ScanComplete
void ScanComplete(void)
Definition: scanmonitor.cpp:98
ChannelUtil::CreateIPTVTuningData
static bool CreateIPTVTuningData(uint channel_id, const IPTVTuningData &tuning)
Definition: channelutil.h:155
ChannelUtil::CreateMultiplex
static uint CreateMultiplex(int sourceid, const QString &sistandard, uint64_t frequency, const QString &modulation, int transport_id=-1, int network_id=-1)
Definition: channelutil.cpp:370
std
Definition: mythchrono.h:23
HDHRChannelFetcher::SetTotalNumChannels
void SetTotalNumChannels(uint val)
Definition: hdhrchannelfetcher.h:106
HDHRChannelFetcher::SetNumChannelsInserted
void SetNumChannelsInserted(uint val)
Definition: hdhrchannelfetcher.cpp:471
mythcontext.h
MThread
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:48
hdhrchannelfetcher.h
HDHRChannelFetcher::~HDHRChannelFetcher
~HDHRChannelFetcher() override
Definition: hdhrchannelfetcher.cpp:259
DTVModulation::kModulation8VSB
@ kModulation8VSB
Definition: dtvconfparserhelpers.h:365
HDHRChannelFetcher::m_serviceType
ServiceRequirements m_serviceType
Definition: hdhrchannelfetcher.h:117
DTVModulationSystem::kModulationSystem_DVBT2
@ kModulationSystem_DVBT2
Definition: dtvconfparserhelpers.h:672
mythdownloadmanager.h
ServiceRequirements
ServiceRequirements
Definition: channelscantypes.h:4
QUERY_CHANNELS
static constexpr const char * QUERY_CHANNELS
Definition: vboxutils.cpp:21
HDHRChannelFetcher::run
void run(void) override
Definition: hdhrchannelfetcher.cpp:305
HDHRChannelFetcher::m_channels
hdhr_chan_map_t * m_channels
Definition: hdhrchannelfetcher.h:118
DTVModulation::kModulationQAM64
@ kModulationQAM64
Definition: dtvconfparserhelpers.h:361
DTVModulationSystem::kModulationSystem_DVBT
@ kModulationSystem_DVBT
Definition: dtvconfparserhelpers.h:659
LOC
#define LOC
Definition: hdhrchannelfetcher.cpp:26
ScanMonitor
Definition: scanmonitor.h:44
HDHRChannelFetcher::m_lock
QMutex m_lock
Definition: hdhrchannelfetcher.h:123
DTVModulation
Definition: dtvconfparserhelpers.h:347
CardUtil::GetVideoDevice
static QString GetVideoDevice(uint inputid)
Definition: cardutil.h:294
ChannelUtil::UpdateIPTVTuningData
static bool UpdateIPTVTuningData(uint channel_id, const IPTVTuningData &tuning)
Definition: channelutil.cpp:1727
DTVModulationSystem::kModulationSystem_DVBC_ANNEX_A
@ kModulationSystem_DVBC_ANNEX_A
Definition: dtvconfparserhelpers.h:657
GetMythDownloadManager
MythDownloadManager * GetMythDownloadManager(void)
Gets the pointer to the MythDownloadManager singleton.
Definition: mythdownloadmanager.cpp:145