MythTV  master
vboxchannelfetcher.cpp
Go to the documentation of this file.
1 // Std C headers
2 #include <cmath>
3 #include <unistd.h>
4 
5 // Qt headers
6 #include <QFile>
7 #include <QTextStream>
8 
9 // MythTV headers
10 #include "mythcontext.h"
11 #include "cardutil.h"
12 #include "channelutil.h"
13 #include "vboxchannelfetcher.h"
14 #include "scanmonitor.h"
15 #include "mythlogging.h"
16 #include "mythdownloadmanager.h"
17 #include "recorders/vboxutils.h"
18 
19 #define LOC QString("VBoxChanFetch: ")
20 
21 VBoxChannelFetcher::VBoxChannelFetcher(uint cardid, const QString &inputname, uint sourceid,
22  bool ftaOnly, ServiceRequirements serviceType,
23  ScanMonitor *monitor) :
24  m_scan_monitor(monitor),
25  m_cardid(cardid), m_inputname(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).arg(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_thread_running)
74  {
75  m_stop_now = true;
76  m_lock.unlock();
77  m_thread->wait(5);
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(500);
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_stop_now = false;
100  m_thread->start();
101 }
102 
104 {
105  m_lock.lock();
106  m_thread_running = 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_stop_now || 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_thread_running = false;
119  m_stop_now = 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_scan_monitor)
127  {
129  m_scan_monitor->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_stop_now || !m_channels)
139  {
140  if (!m_channels && m_scan_monitor)
141  {
142  m_scan_monitor->ScanAppendTextToLog(QCoreApplication::translate("(Common)", "Error"));
144  m_scan_monitor->ScanErrored(tr("Downloading Channel List Failed"));
145  }
146  QMutexLocker locker(&m_lock);
147  m_thread_running = false;
148  m_stop_now = true;
149  return;
150  }
151 
152  // Step 3/3 : Process
153  if (m_scan_monitor)
154  {
156  m_scan_monitor->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->begin();
166  for (uint i = 1; it != m_channels->end(); ++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).arg(name);
180 
181  LOG(VB_CHANNEL, LOG_INFO, QString("Handling channel %1 %2")
182  .arg(channum).arg(name));
183  uint mplexID = 0;
184  if (m_ftaOnly && !fta)
185  {
186  // ignore this encrypted channel
187  if (m_scan_monitor)
188  {
189  m_scan_monitor->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_scan_monitor)
197  {
198  m_scan_monitor->ScanAppendTextToLog(tr("Ignoring Radio %1")
199  .arg(msg));
200  }
201  }
202  else if (!SupportedTransmission(transType))
203  {
204  // ignore this channel
205  if (m_scan_monitor)
206  {
207  m_scan_monitor->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_scan_monitor)
217  {
218  m_scan_monitor->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, false, false, QString(),
232  QString(), "Default", xmltvid);
233 
234  ChannelUtil::CreateIPTVTuningData(chanid, (*it).m_tuning);
235  }
236  else
237  {
238  if (m_scan_monitor)
239  {
240  m_scan_monitor->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, false, false, QString(),
252  QString(), "Default", QString());
253 
254  ChannelUtil::UpdateIPTVTuningData(chanid, (*it).m_tuning);
255  }
256  }
257 
259  }
260 
261  if (m_scan_monitor)
262  {
263  m_scan_monitor->ScanAppendTextToLog(tr("Done"));
267  }
268 
269  QMutexLocker locker(&m_lock);
270  m_thread_running = false;
271  m_stop_now = true;
272 }
273 
275 {
276  uint minval = 70, range = 100 - minval;
277  uint pct = minval + (uint) truncf((((float)val) / m_chan_cnt) * range);
278  if (m_scan_monitor)
280 }
281 
282 bool VBoxChannelFetcher::SupportedTransmission(const QString& transType)
283 {
284  if (transType == "UNKNOWN")
285  return true;
286 
287  // both S and S2 tuners can tune an S channel
288  if (transType == "S" && (m_transType == "S" || m_transType == "S2"))
289  return true;
290 
291  // both T and T2 tuners can tune a T channel
292  if (transType == "T" && (m_transType == "T" || m_transType == "T2"))
293  return true;
294 
295  // for S2, T2, A and C the channel and tuner transmission types must match
296  return transType == m_transType;
297 }
void start(QThread::Priority=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:294
VBoxChannelFetcher(uint cardid, const QString &inputname, uint sourceid, bool ftaOnly, ServiceRequirements serviceType, ScanMonitor *monitor=nullptr)
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, bool hidden, bool hidden_in_guide, const QString &freqid, QString icon=QString(), QString format="Default", QString xmltvid=QString(), QString default_authority=QString())
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:46
#define LOC
static bool UpdateIPTVTuningData(uint channel_id, const IPTVTuningData &tuning)
Definition: vboxutils.h:13
bool wait(unsigned long time=ULONG_MAX)
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:311
static QString getIPFromVideoDevice(const QString &dev)
Definition: vboxutils.cpp:151
void ScanPercentComplete(int pct)
unsigned int uint
Definition: compat.h:140
vbox_chan_map_t GetChannels(void)
QMap< QString, VBoxChannelInfo > vbox_chan_map_t
void ScanErrored(const QString &error)
bool SupportedTransmission(const QString &transType)
static int GetChanID(int db_mplexid, int service_transport_id, int major_channel, int minor_channel, int program_number)
void run(void) override
void ScanAppendTextToLog(const QString &status)
static bool CreateIPTVTuningData(uint channel_id, const IPTVTuningData &tuning)
Definition: channelutil.h:140
const char * name
Definition: ParseText.cpp:328
static int CreateChanID(uint sourceid, const QString &chan_num)
Creates a unique channel ID for database use.
vbox_chan_map_t * m_channels
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, bool hidden, bool hidden_in_guide, const QString &freqid=QString(), const QString &icon=QString(), QString format=QString(), const QString &xmltvid=QString(), const QString &default_authority=QString())
static QString GetVideoDevice(uint inputid)
Definition: cardutil.h:273
ScanMonitor * m_scan_monitor
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
vbox_chan_map_t * getChannels(void)
Definition: vboxutils.cpp:295
ServiceRequirements
void ScanComplete(void)
Definition: scanmonitor.cpp:98
ServiceRequirements m_serviceType
bool isFinished(void) const
Definition: mthread.cpp:269
static uint CreateMultiplex(int sourceid, QString sistandard, uint64_t frequency, QString modulation, int transport_id=-1, int network_id=-1)
void Stop(void)
Stops the scanning thread running.
void SetTotalNumChannels(uint val)