MythTV  master
hdhrstreamhandler.cpp
Go to the documentation of this file.
1 // -*- Mode: c++ -*-
2 
3 // POSIX headers
4 #include <fcntl.h>
5 #include <unistd.h>
6 #ifndef _WIN32
7 #include <sys/select.h>
8 #include <sys/ioctl.h>
9 #endif
10 #include <chrono> // for milliseconds
11 #include <thread> // for sleep_for
12 
13 // MythTV headers
15 
16 #include "cardutil.h"
17 #include "dtvsignalmonitor.h"
18 #include "hdhrchannel.h"
19 #include "hdhrstreamhandler.h"
20 #include "mpeg/mpegstreamdata.h"
21 #include "mpeg/streamlisteners.h"
22 
23 #define LOC QString("HDHRSH[%1](%2): ").arg(m_inputId).arg(m_device)
24 
25 QMap<int,HDHRStreamHandler*> HDHRStreamHandler::s_handlers;
28 
29 HDHRStreamHandler *HDHRStreamHandler::Get(const QString &devname,
30  int inputid, int majorid)
31 {
32  QMutexLocker locker(&s_handlersLock);
33 
34  QMap<int,HDHRStreamHandler*>::iterator it = s_handlers.find(majorid);
35 
36  if (it == s_handlers.end())
37  {
38  auto *newhandler = new HDHRStreamHandler(devname, inputid, majorid);
39  newhandler->Open();
40  s_handlers[majorid] = newhandler;
41  s_handlersRefCnt[majorid] = 1;
42 
43  LOG(VB_RECORD, LOG_INFO,
44  QString("HDHRSH[%1]: Creating new stream handler %2 for %3")
45  .arg(inputid).arg(majorid).arg(devname));
46  }
47  else
48  {
49  s_handlersRefCnt[majorid]++;
50  uint rcount = s_handlersRefCnt[majorid];
51  LOG(VB_RECORD, LOG_INFO,
52  QString("HDHRSH[%1]: Using existing stream handler %2 for %3")
53  .arg(inputid).arg(majorid)
54  .arg(devname) + QString(" (%1 in use)").arg(rcount));
55  }
56 
57  return s_handlers[majorid];
58 }
59 
60 void HDHRStreamHandler::Return(HDHRStreamHandler * & ref, int inputid)
61 {
62  QMutexLocker locker(&s_handlersLock);
63 
64  int majorid = ref->m_majorId;
65 
66  QMap<int,uint>::iterator rit = s_handlersRefCnt.find(majorid);
67  if (rit == s_handlersRefCnt.end())
68  return;
69 
70  QMap<int,HDHRStreamHandler*>::iterator it = s_handlers.find(majorid);
71  if (*rit > 1)
72  {
73  ref = nullptr;
74  (*rit)--;
75  return;
76  }
77 
78  if ((it != s_handlers.end()) && (*it == ref))
79  {
80  LOG(VB_RECORD, LOG_INFO, QString("HDHRSH[%1]: Closing handler for %2")
81  .arg(inputid).arg(majorid));
82  ref->Close();
83  delete *it;
84  s_handlers.erase(it);
85  }
86  else
87  {
88  LOG(VB_GENERAL, LOG_ERR,
89  QString("HDHRSH[%1] Error: Couldn't find handler for %2")
90  .arg(inputid).arg(majorid));
91  }
92 
93  s_handlersRefCnt.erase(rit);
94  ref = nullptr;
95 }
96 
97 HDHRStreamHandler::HDHRStreamHandler(const QString &device, int inputid,
98  int majorid)
99  : StreamHandler(device, inputid)
100  , m_majorId(majorid)
101 {
102  setObjectName("HDHRStreamHandler");
103 }
104 
109 {
110  RunProlog();
111 
112  {
113  QMutexLocker locker(&m_hdhrLock);
114 
115  /* Create TS socket. */
116  if (!hdhomerun_device_stream_start(m_hdhomerunDevice))
117  {
118  LOG(VB_GENERAL, LOG_ERR, LOC +
119  "Starting recording (set target failed). Aborting.");
120  m_bError = true;
121  RunEpilog();
122  return;
123  }
124  hdhomerun_device_stream_flush(m_hdhomerunDevice);
125  }
126 
127  SetRunning(true, false, false);
128 
129  LOG(VB_RECORD, LOG_INFO, LOC + "RunTS(): begin");
130 
131  int remainder = 0;
132  QElapsedTimer last_update;
133  while (m_runningDesired && !m_bError)
134  {
135  auto elapsed = !last_update.isValid()
136  ? -1ms : std::chrono::milliseconds(last_update.elapsed());
137  elapsed = (elapsed < 0ms) ? 1s : elapsed;
138  if (elapsed > 100ms)
139  {
142  UpdateFilters();
143  last_update.restart();
144  }
145 
146  size_t read_size = VIDEO_DATA_BUFFER_SIZE_1S / 8; // read up to 1/8s
147  read_size /= VIDEO_DATA_PACKET_SIZE;
148  read_size *= VIDEO_DATA_PACKET_SIZE;
149 
150  size_t data_length = 0;
151  unsigned char *data_buffer = hdhomerun_device_stream_recv(
152  m_hdhomerunDevice, read_size, &data_length);
153 
154  if (!data_buffer)
155  {
156  std::this_thread::sleep_for(20ms);
157  continue;
158  }
159 
160  // Assume data_length is a multiple of 188 (packet size)
161 
162  m_listenerLock.lock();
163 
164  if (m_streamDataList.empty())
165  {
166  m_listenerLock.unlock();
167  continue;
168  }
169 
170  for (auto sit = m_streamDataList.cbegin(); sit != m_streamDataList.cend(); ++sit)
171  remainder = sit.key()->ProcessData(data_buffer, data_length);
172 
173  WriteMPTS(data_buffer, data_length - remainder);
174 
175  m_listenerLock.unlock();
176  if (remainder != 0)
177  {
178  LOG(VB_RECORD, LOG_INFO, LOC +
179  QString("RunTS(): data_length = %1 remainder = %2")
180  .arg(data_length).arg(remainder));
181  }
182  }
183  LOG(VB_RECORD, LOG_INFO, LOC + "RunTS(): " + "shutdown");
184 
186  {
188  }
189 
190  {
191  QMutexLocker locker(&m_hdhrLock);
192  hdhomerun_device_stream_stop(m_hdhomerunDevice);
193  }
194 
195  if (VERBOSE_LEVEL_CHECK(VB_RECORD, LOG_INFO))
196  {
197  struct hdhomerun_video_sock_t* vs = nullptr;
198  struct hdhomerun_video_stats_t stats {};
199  vs = hdhomerun_device_get_video_sock(m_hdhomerunDevice);
200  if (vs)
201  {
202  hdhomerun_video_get_stats(vs, &stats);
203  LOG(VB_RECORD, LOG_INFO, LOC +
204  QString("stream stats: packet_count=%1 "
205  "network_errors=%2 "
206  "transport_errors=%3 "
207  "sequence_errors=%4 "
208  "overflow_errors=%5")
209  .arg(stats.packet_count)
210  .arg(stats.network_error_count)
211  .arg(stats.transport_error_count)
212  .arg(stats.sequence_error_count)
213  .arg(stats.overflow_error_count));
214  }
215  }
216 
217  LOG(VB_RECORD, LOG_INFO, LOC + "RunTS(): " + "end");
218 
219  SetRunning(false, false, false);
220 
221  RunEpilog();
222 }
223 
224 static QString filt_str(uint pid)
225 {
226  uint pid0 = (pid / (16*16*16)) % 16;
227  uint pid1 = (pid / (16*16)) % 16;
228  uint pid2 = (pid / (16)) % 16;
229  uint pid3 = pid % 16;
230  return QString("0x%1%2%3%4")
231  .arg(pid0,0,16).arg(pid1,0,16)
232  .arg(pid2,0,16).arg(pid3,0,16);
233 }
234 
236 {
239 
241  {
242  LOG(VB_GENERAL, LOG_ERR, LOC +
243  QString("UpdateFilters called in wrong tune mode, %1")
244  .arg(m_tuneMode));
245  return false;
246  }
247 
248 #ifdef DEBUG_PID_FILTERS
249  LOG(VB_RECORD, LOG_DEBUG, LOC + "UpdateFilters()");
250 #endif // DEBUG_PID_FILTERS
251  QMutexLocker locker(&m_pidLock);
252 
253  if (!m_filtersChanged)
254  {
255  return true;
256  }
257 
258  QString filter = "";
259 
260  std::vector<uint> range_min;
261  std::vector<uint> range_max;
262 
263  for (auto it = m_pidInfo.cbegin(); it != m_pidInfo.cend(); ++it)
264  {
265  range_min.push_back(it.key());
266  PIDInfoMap::const_iterator eit = it;
267  for (++eit;
268  (eit != m_pidInfo.cend()) && (it.key() + 1 == eit.key());
269  ++it, ++eit);
270  range_max.push_back(it.key());
271  }
272  if (range_min.size() > 16)
273  {
274  range_min.resize(16);
275  uint pid_max = range_max.back();
276  range_max.resize(15);
277  range_max.push_back(pid_max);
278  }
279 
280  for (size_t i = 0; i < range_min.size(); i++)
281  {
282  filter += filt_str(range_min[i]);
283  if (range_min[i] != range_max[i])
284  filter += QString("-%1").arg(filt_str(range_max[i]));
285  filter += " ";
286  }
287 
288  filter = filter.trimmed();
289 
290  QString new_filter = TunerSet("filter", filter);
291 
292 #ifdef DEBUG_PID_FILTERS
293  QString msg = QString("Filter: '%1'").arg(filter);
294  if (filter != new_filter)
295  msg += QString("\n\t\t\t\t'%2'").arg(new_filter);
296 
297  LOG(VB_RECORD, LOG_DEBUG, LOC + msg);
298 #endif // DEBUG_PID_FILTERS
299 
300  m_filtersChanged = false;
301 
302  return filter == new_filter;
303 }
304 
306 {
307  if (Connect())
308  {
309  const char *model = hdhomerun_device_get_model_str(m_hdhomerunDevice);
310  m_tunerTypes.clear();
311  if (QString(model).contains("cablecard", Qt::CaseInsensitive))
312  {
313  QString status_channel = "none";
314  hdhomerun_tuner_status_t t_status {};
315 
316  if (hdhomerun_device_get_oob_status(
317  m_hdhomerunDevice, nullptr, &t_status) < 0)
318  {
319  LOG(VB_GENERAL, LOG_ERR, LOC +
320  "Failed to query Cable card OOB channel");
321  }
322  else
323  {
324  status_channel = QString(t_status.channel);
325  LOG(VB_RECORD, LOG_INFO, LOC +
326  QString("Cable card OOB channel is '%1'")
327  .arg(status_channel));
328  }
329 
330  if (status_channel == "none")
331  {
332  LOG(VB_RECORD, LOG_INFO, LOC + "Cable card is not present");
334  }
335  else
336  {
337  LOG(VB_RECORD, LOG_INFO, LOC + "Cable card is present");
339  }
340  }
341  else if (QString(model).endsWith("dvbt", Qt::CaseInsensitive))
342  {
344  }
345  else if (QString(model).endsWith("dvbc", Qt::CaseInsensitive))
346  {
348  }
349  else if (QString(model).endsWith("dvbtc", Qt::CaseInsensitive))
350  {
353  }
354  else
355  {
357  }
358 
359  return true;
360  }
361  return false;
362 }
363 
365 {
366  if (m_hdhomerunDevice)
367  {
368  TuneChannel("none");
369  hdhomerun_device_tuner_lockkey_release(m_hdhomerunDevice);
370  m_hdhomerunDevice = nullptr;
371  }
372  if (m_deviceSelector)
373  {
374  hdhomerun_device_selector_destroy(m_deviceSelector, true);
375  m_deviceSelector = nullptr;
376  }
377 }
378 
380 {
381  m_deviceSelector = hdhomerun_device_selector_create(nullptr);
382  if (!m_deviceSelector)
383  {
384  LOG(VB_GENERAL, LOG_ERR, LOC + "Unable to create device selector");
385  return false;
386  }
387 
388  QStringList devices = m_device.split(",");
389  for (const QString& device : std::as_const(devices))
390  {
391  QByteArray ba = device.toUtf8();
392  int n = hdhomerun_device_selector_load_from_str(
393  m_deviceSelector, ba.data());
394  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Added %1 devices from %3")
395  .arg(n).arg(device));
396  }
397 
398  m_hdhomerunDevice = hdhomerun_device_selector_choose_and_lock(
399  m_deviceSelector, nullptr);
400  if (!m_hdhomerunDevice)
401  {
402  LOG(VB_GENERAL, LOG_ERR, LOC +
403  QString("Unable to find a free device"));
404  hdhomerun_device_selector_destroy(m_deviceSelector, true);
405  m_deviceSelector = nullptr;
406  return false;
407  }
408 
409  m_tuner = hdhomerun_device_get_tuner(m_hdhomerunDevice);
410 
411  LOG(VB_GENERAL, LOG_INFO, LOC +
412  QString("Connected to device(%1)")
413  .arg(hdhomerun_device_get_name(m_hdhomerunDevice)));
414 
415  return true;
416 }
417 
418 QString HDHRStreamHandler::TunerGet(const QString &name)
419 {
420  QMutexLocker locker(&m_hdhrLock);
421 
422  if (!m_hdhomerunDevice)
423  {
424  LOG(VB_GENERAL, LOG_ERR, LOC + "Get request failed (not connected)");
425  return {};
426  }
427 
428  QString valname = QString("/tuner%1/%2").arg(m_tuner).arg(name);
429  char *value = nullptr;
430  char *error = nullptr;
431  if (hdhomerun_device_get_var(
432  m_hdhomerunDevice, valname.toLocal8Bit().constData(),
433  &value, &error) < 0)
434  {
435  LOG(VB_GENERAL, LOG_ERR, LOC +
436  QString("Get %1 request failed").arg(valname) + ENO);
437  return {};
438  }
439 
440  if (error)
441  {
442  LOG(VB_GENERAL, LOG_ERR, LOC + QString("DeviceGet(%1): %2")
443  .arg(name, error));
444  return {};
445  }
446 
447  return {value};
448 }
449 
450 QString HDHRStreamHandler::TunerSet(const QString &name, const QString &val)
451 {
452  QMutexLocker locker(&m_hdhrLock);
453 
454  if (!m_hdhomerunDevice)
455  {
456  LOG(VB_GENERAL, LOG_ERR, LOC + "Set request failed (not connected)");
457  return {};
458  }
459 
460  QString valname = QString("/tuner%1/%2").arg(m_tuner).arg(name);
461  char *value = nullptr;
462  char *error = nullptr;
463 
464 #if 0
465  LOG(VB_CHANSCAN, LOG_DEBUG, LOC + valname + " " + val);
466 #endif
467 
468  // Receive full transport stream when pid 0x2000 is present
469  QString val2 = val;
470  if (name.contains("filter") && val.contains("0x2000"))
471  {
472  val2 = "0x0000-0x1FFF";
473  LOG(VB_RECORD, LOG_INFO, LOC + valname + " fixup: \"" + val + "\" to \"" +val2 + "\"");
474  }
475 
476  if (hdhomerun_device_set_var(
477  m_hdhomerunDevice, valname.toLocal8Bit().constData(),
478  val2.toLocal8Bit().constData(), &value, &error) < 0)
479  {
480  LOG(VB_GENERAL, LOG_ERR, LOC +
481  QString("Set %1 to '%2' request failed").arg(valname, val2) +
482  ENO);
483  return {};
484  }
485 
486  if (error)
487  {
488  // Terminate recording when HDHomeRun lost connection
489  if (strstr(error, "ERROR: lock no longer held"))
490  m_bError = true;
491 
492  LOG(VB_GENERAL, LOG_ERR, LOC + QString("DeviceSet(%1 %2): %3")
493  .arg(name, val2, error));
494  return {};
495  }
496 
497  return {value};
498 }
499 
500 void HDHRStreamHandler::GetTunerStatus(struct hdhomerun_tuner_status_t *status)
501 {
502  QMutexLocker locker(&m_hdhrLock);
503 
504  hdhomerun_device_get_tuner_status(m_hdhomerunDevice, nullptr, status);
505 }
506 
508 {
509  return (m_hdhomerunDevice != nullptr);
510 }
511 
512 bool HDHRStreamHandler::TuneChannel(const QString &chanid)
513 {
515 
516  QString current = TunerGet("channel");
517  if (current == chanid)
518  {
519  LOG(VB_RECORD, LOG_INFO, LOC + QString("Not Re-Tuning channel %1")
520  .arg(chanid));
521  return true;
522  }
523 
524  LOG(VB_RECORD, LOG_INFO, LOC + QString("Tuning channel %1 (was %2)")
525  .arg(chanid, current));
526  return !TunerSet("channel", chanid).isEmpty();
527 }
528 
530 {
533 
535  {
536  LOG(VB_GENERAL, LOG_ERR, LOC +
537  QString("TuneProgram called in wrong tune mode, %1")
538  .arg(m_tuneMode));
539  return false;
540  }
541 
542  LOG(VB_RECORD, LOG_INFO, LOC + QString("Tuning program %1")
543  .arg(mpeg_prog_num));
544  return !TunerSet(
545  "program", QString::number(mpeg_prog_num)).isEmpty();
546 }
547 
548 bool HDHRStreamHandler::TuneVChannel(const QString &vchn)
549 {
551 
552  QString current = TunerGet("vchannel");
553  if (current == vchn)
554  {
555  LOG(VB_RECORD, LOG_INFO, LOC + QString("Not Re-Tuning channel %1")
556  .arg(vchn));
557  return true;
558  }
559  LOG(VB_RECORD, LOG_INFO, LOC + QString("TuneVChannel(%1) from (%2)")
560  .arg(vchn, current));
561 
562  LOG(VB_RECORD, LOG_INFO, LOC + QString("Tuning vchannel %1").arg(vchn));
563  return !TunerSet("vchannel", vchn).isEmpty();
564 }
ENO
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:74
HDHRStreamHandler::Close
void Close(void)
Definition: hdhrstreamhandler.cpp:364
DTVTunerType::kTunerTypeDVBC
static const int kTunerTypeDVBC
Definition: dtvconfparserhelpers.h:95
HDHRStreamHandler::run
void run(void) override
Reads HDHomeRun socket for tables & data.
Definition: hdhrstreamhandler.cpp:108
StreamHandler::RemoveAllPIDFilters
bool RemoveAllPIDFilters(void)
Definition: streamhandler.cpp:240
StreamHandler::SetRunning
void SetRunning(bool running, bool using_buffering, bool using_section_reader)
Definition: streamhandler.cpp:173
HDHRStreamHandler::TunerSet
QString TunerSet(const QString &name, const QString &value)
Definition: hdhrstreamhandler.cpp:450
StreamHandler::WriteMPTS
void WriteMPTS(const unsigned char *buffer, uint len)
Write out a copy of the raw MPTS.
Definition: streamhandler.cpp:355
HDHRStreamHandler::TunerGet
QString TunerGet(const QString &name)
Definition: hdhrstreamhandler.cpp:418
StreamHandler
Definition: streamhandler.h:56
VERBOSE_LEVEL_CHECK
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
Definition: mythlogging.h:29
MThread::setObjectName
void setObjectName(const QString &name)
Definition: mthread.cpp:238
HDHRStreamHandler::m_tunerTypes
std::vector< DTVTunerType > m_tunerTypes
Definition: hdhrstreamhandler.h:90
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MThread::RunProlog
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:196
HDHRStreamHandler::s_handlersRefCnt
static QMap< int, uint > s_handlersRefCnt
Definition: hdhrstreamhandler.h:99
HDHRStreamHandler::m_deviceSelector
hdhomerun_device_selector_t * m_deviceSelector
Definition: hdhrstreamhandler.h:88
HDHRStreamHandler::Connect
bool Connect(void)
Definition: hdhrstreamhandler.cpp:379
LOC
#define LOC
Definition: hdhrstreamhandler.cpp:23
streamlisteners.h
hdhrTuneModeFrequencyProgram
@ hdhrTuneModeFrequencyProgram
Definition: hdhrstreamhandler.h:37
HDHRStreamHandler::TuneVChannel
bool TuneVChannel(const QString &vchn)
Definition: hdhrstreamhandler.cpp:548
StreamHandler::m_filtersChanged
bool m_filtersChanged
Definition: streamhandler.h:135
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
hdhrTuneModeVChannel
@ hdhrTuneModeVChannel
Definition: hdhrstreamhandler.h:38
StreamHandler::m_listenerLock
QRecursiveMutex m_listenerLock
Definition: streamhandler.h:144
StreamHandler::m_pidInfo
PIDInfoMap m_pidInfo
Definition: streamhandler.h:133
mythlogging.h
HDHRStreamHandler::Return
static void Return(HDHRStreamHandler *&ref, int inputid)
Definition: hdhrstreamhandler.cpp:60
StreamHandler::m_pidLock
QRecursiveMutex m_pidLock
Definition: streamhandler.h:131
StreamHandler::UpdateFiltersFromStreamData
bool UpdateFiltersFromStreamData(void)
Definition: streamhandler.cpp:290
filt_str
static QString filt_str(uint pid)
Definition: hdhrstreamhandler.cpp:224
MThread::RunEpilog
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:209
HDHRStreamHandler::m_hdhomerunDevice
hdhomerun_device_t * m_hdhomerunDevice
Definition: hdhrstreamhandler.h:87
HDHRStreamHandler::IsConnected
bool IsConnected(void) const
Definition: hdhrstreamhandler.cpp:507
HDHRStreamHandler::m_tuneMode
HDHRTuneMode m_tuneMode
Definition: hdhrstreamhandler.h:91
mpegstreamdata.h
HDHRStreamHandler::HDHRStreamHandler
HDHRStreamHandler(const QString &device, int inputid, int majorid)
Definition: hdhrstreamhandler.cpp:97
hardwareprofile.smolt.error
def error(message)
Definition: smolt.py:410
HDHRStreamHandler
Definition: hdhrstreamhandler.h:47
HDHRStreamHandler::m_tuner
int m_tuner
Definition: hdhrstreamhandler.h:89
HDHRStreamHandler::Open
bool Open(void)
Definition: hdhrstreamhandler.cpp:305
HDHRStreamHandler::TuneChannel
bool TuneChannel(const QString &chanid)
Definition: hdhrstreamhandler.cpp:512
cardutil.h
StreamHandler::m_runningDesired
volatile bool m_runningDesired
Definition: streamhandler.h:119
HDHRStreamHandler::m_hdhrLock
QRecursiveMutex m_hdhrLock
Definition: hdhrstreamhandler.h:94
HDHRStreamHandler::m_majorId
int m_majorId
Definition: hdhrstreamhandler.h:92
HDHRStreamHandler::GetTunerStatus
void GetTunerStatus(struct hdhomerun_tuner_status_t *status)
Definition: hdhrstreamhandler.cpp:500
HDHRStreamHandler::UpdateFilters
bool UpdateFilters(void) override
Definition: hdhrstreamhandler.cpp:235
DTVTunerType::kTunerTypeOCUR
static const int kTunerTypeOCUR
Definition: dtvconfparserhelpers.h:101
StreamHandler::m_streamDataList
StreamDataList m_streamDataList
Definition: streamhandler.h:145
StreamHandler::m_bError
volatile bool m_bError
Definition: streamhandler.h:124
DTVTunerType::kTunerTypeATSC
static const int kTunerTypeATSC
Definition: dtvconfparserhelpers.h:98
HDHRStreamHandler::TuneProgram
bool TuneProgram(uint mpeg_prog_num)
Definition: hdhrstreamhandler.cpp:529
HDHRStreamHandler::Get
static HDHRStreamHandler * Get(const QString &devname, int inputid, int majorid)
Definition: hdhrstreamhandler.cpp:29
hdhrstreamhandler.h
DTVTunerType::kTunerTypeDVBT
static const int kTunerTypeDVBT
Definition: dtvconfparserhelpers.h:96
HDHRStreamHandler::s_handlersLock
static QMutex s_handlersLock
Definition: hdhrstreamhandler.h:97
hdhrTuneModeFrequencyPid
@ hdhrTuneModeFrequencyPid
Definition: hdhrstreamhandler.h:36
hdhrchannel.h
StreamHandler::m_device
QString m_device
Definition: streamhandler.h:111
hdhrTuneModeFrequency
@ hdhrTuneModeFrequency
Definition: hdhrstreamhandler.h:35
dtvsignalmonitor.h
uint
unsigned int uint
Definition: freesurround.h:24
HDHRStreamHandler::s_handlers
static QMap< int, HDHRStreamHandler * > s_handlers
Definition: hdhrstreamhandler.h:98