4#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
5#include <QtSystemDetection>
12#include <sys/select.h>
28#define LOC QString("HDHRSH[%1](%2): ").arg(m_inputId).arg(m_device)
35 int inputid,
int majorid)
39 QMap<int,HDHRStreamHandler*>::iterator it =
s_handlers.find(majorid);
48 LOG(VB_RECORD, LOG_INFO,
49 QString(
"HDHRSH[%1]: Creating new stream handler %2 for %3")
50 .arg(inputid).arg(majorid).arg(devname));
56 LOG(VB_RECORD, LOG_INFO,
57 QString(
"HDHRSH[%1]: Using existing stream handler %2 for %3")
58 .arg(inputid).arg(majorid)
59 .arg(devname) + QString(
" (%1 in use)").arg(rcount));
75 QMap<int,HDHRStreamHandler*>::iterator it =
s_handlers.find(majorid);
85 LOG(VB_RECORD, LOG_INFO, QString(
"HDHRSH[%1]: Closing handler for %2")
86 .arg(inputid).arg(majorid));
93 LOG(VB_GENERAL, LOG_ERR,
94 QString(
"HDHRSH[%1] Error: Couldn't find handler for %2")
95 .arg(inputid).arg(majorid));
123 LOG(VB_GENERAL, LOG_ERR,
LOC +
124 "Starting recording (set target failed). Aborting.");
134 LOG(VB_RECORD, LOG_INFO,
LOC +
"RunTS(): begin");
137 QElapsedTimer last_update;
140 auto elapsed = !last_update.isValid()
141 ? -1ms : std::chrono::milliseconds(last_update.elapsed());
142 elapsed = (elapsed < 0ms) ? 1s : elapsed;
148 last_update.restart();
151 size_t read_size = VIDEO_DATA_BUFFER_SIZE_1S / 8;
152 read_size /= VIDEO_DATA_PACKET_SIZE;
153 read_size *= VIDEO_DATA_PACKET_SIZE;
155 size_t data_length = 0;
156 unsigned char *data_buffer = hdhomerun_device_stream_recv(
161 std::this_thread::sleep_for(20ms);
176 remainder = sit.key()->ProcessData(data_buffer, data_length);
178 WriteMPTS(data_buffer, data_length - remainder);
183 LOG(VB_RECORD, LOG_INFO,
LOC +
184 QString(
"RunTS(): data_length = %1 remainder = %2")
185 .arg(data_length).arg(remainder));
188 LOG(VB_RECORD, LOG_INFO,
LOC +
"RunTS(): " +
"shutdown");
202 struct hdhomerun_video_sock_t* vs =
nullptr;
203 struct hdhomerun_video_stats_t stats {};
207 hdhomerun_video_get_stats(vs, &stats);
208 LOG(VB_RECORD, LOG_INFO,
LOC +
209 QString(
"stream stats: packet_count=%1 "
211 "transport_errors=%3 "
212 "sequence_errors=%4 "
213 "overflow_errors=%5")
214 .arg(stats.packet_count)
215 .arg(stats.network_error_count)
216 .arg(stats.transport_error_count)
217 .arg(stats.sequence_error_count)
218 .arg(stats.overflow_error_count));
222 LOG(VB_RECORD, LOG_INFO,
LOC +
"RunTS(): " +
"end");
231 uint pid0 = (pid / (16*16*16)) % 16;
232 uint pid1 = (pid / (16*16)) % 16;
233 uint pid2 = (pid / (16)) % 16;
234 uint pid3 = pid % 16;
235 return QString(
"0x%1%2%3%4")
236 .arg(pid0,0,16).arg(pid1,0,16)
237 .arg(pid2,0,16).arg(pid3,0,16);
247 LOG(VB_GENERAL, LOG_ERR,
LOC +
248 QString(
"UpdateFilters called in wrong tune mode, %1")
253#ifdef DEBUG_PID_FILTERS
254 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"UpdateFilters()");
265 std::vector<uint> range_min;
266 std::vector<uint> range_max;
270 range_min.push_back(it.key());
271 PIDInfoMap::const_iterator eit = it;
273 (eit !=
m_pidInfo.cend()) && (it.key() + 1 == eit.key());
275 range_max.push_back(it.key());
277 if (range_min.size() > 16)
279 range_min.resize(16);
280 uint pid_max = range_max.back();
281 range_max.resize(15);
282 range_max.push_back(pid_max);
285 for (
size_t i = 0; i < range_min.size(); i++)
288 if (range_min[i] != range_max[i])
289 filter += QString(
"-%1").arg(
filt_str(range_max[i]));
293 filter = filter.trimmed();
295 QString new_filter =
TunerSet(
"filter", filter);
297#ifdef DEBUG_PID_FILTERS
298 QString msg = QString(
"Filter: '%1'").arg(filter);
299 if (filter != new_filter)
300 msg += QString(
"\n\t\t\t\t'%2'").arg(new_filter);
302 LOG(VB_RECORD, LOG_DEBUG,
LOC + msg);
307 return filter == new_filter;
316 if (QString(model).contains(
"cablecard", Qt::CaseInsensitive))
318 QString status_channel =
"none";
319 hdhomerun_tuner_status_t t_status {};
321 if (hdhomerun_device_get_oob_status(
324 LOG(VB_GENERAL, LOG_ERR,
LOC +
325 "Failed to query Cable card OOB channel");
329 status_channel = QString(t_status.channel);
330 LOG(VB_RECORD, LOG_INFO,
LOC +
331 QString(
"Cable card OOB channel is '%1'")
332 .arg(status_channel));
335 if (status_channel ==
"none")
337 LOG(VB_RECORD, LOG_INFO,
LOC +
"Cable card is not present");
342 LOG(VB_RECORD, LOG_INFO,
LOC +
"Cable card is present");
346 else if (QString(model).endsWith(
"dvbt", Qt::CaseInsensitive))
350 else if (QString(model).endsWith(
"dvbc", Qt::CaseInsensitive))
354 else if (QString(model).endsWith(
"dvbtc", Qt::CaseInsensitive))
389 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unable to create device selector");
393 QStringList devices =
m_device.split(
",");
394 for (
const QString& device : std::as_const(devices))
396 QByteArray ba = device.toUtf8();
397 int n = hdhomerun_device_selector_load_from_str(
399 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Added %1 devices from %3")
400 .arg(n).arg(device));
407 LOG(VB_GENERAL, LOG_ERR,
LOC +
408 QString(
"Unable to find a free device"));
416 LOG(VB_GENERAL, LOG_INFO,
LOC +
417 QString(
"Connected to device(%1)")
429 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Get request failed (not connected)");
433 QString valname = QString(
"/tuner%1/%2").arg(
m_tuner).arg(name);
434 char *value =
nullptr;
435 char *
error =
nullptr;
436 if (hdhomerun_device_get_var(
440 LOG(VB_GENERAL, LOG_ERR,
LOC +
441 QString(
"Get %1 request failed").arg(valname) +
ENO);
447 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"DeviceGet(%1): %2")
461 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Set request failed (not connected)");
465 QString valname = QString(
"/tuner%1/%2").arg(
m_tuner).arg(name);
466 char *value =
nullptr;
467 char *
error =
nullptr;
470 LOG(VB_CHANSCAN, LOG_DEBUG,
LOC + valname +
" " + val);
475 if (name.contains(
"filter") && val.contains(
"0x2000"))
477 val2 =
"0x0000-0x1FFF";
478 LOG(VB_RECORD, LOG_INFO,
LOC + valname +
" fixup: \"" + val +
"\" to \"" +val2 +
"\"");
481 if (hdhomerun_device_set_var(
483 val2.toLocal8Bit().constData(), &value, &
error) < 0)
485 LOG(VB_GENERAL, LOG_ERR,
LOC +
486 QString(
"Set %1 to '%2' request failed").arg(valname, val2) +
494 if (strstr(
error,
"ERROR: lock no longer held"))
497 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"DeviceSet(%1 %2): %3")
498 .arg(name, val2,
error));
524 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"Not Re-Tuning channel %1")
529 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"Tuning channel %1 (was %2)")
531 return !
TunerSet(
"channel", chanid).isEmpty();
541 LOG(VB_GENERAL, LOG_ERR,
LOC +
542 QString(
"TuneProgram called in wrong tune mode, %1")
547 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"Tuning program %1")
548 .arg(mpeg_prog_num));
550 "program", QString::number(mpeg_prog_num)).isEmpty();
560 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"Not Re-Tuning channel %1")
564 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"TuneVChannel(%1) from (%2)")
567 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"Tuning vchannel %1").arg(vchn));
568 return !
TunerSet(
"vchannel", vchn).isEmpty();
static const int kTunerTypeOCUR
static const int kTunerTypeDVBT
static const int kTunerTypeDVBC
static const int kTunerTypeATSC
QRecursiveMutex m_hdhrLock
void GetTunerStatus(struct hdhomerun_tuner_status_t *status)
static QMutex s_handlersLock
bool TuneVChannel(const QString &vchn)
hdhomerun_device_t * m_hdhomerunDevice
bool UpdateFilters(void) override
std::vector< DTVTunerType > m_tunerTypes
HDHRStreamHandler(const QString &device, int inputid, int majorid)
bool TuneProgram(uint mpeg_prog_num)
void run(void) override
Reads HDHomeRun socket for tables & data.
static HDHRStreamHandler * Get(const QString &devname, int inputid, int majorid)
static QMap< int, uint > s_handlersRefCnt
static QMap< int, HDHRStreamHandler * > s_handlers
bool TuneChannel(const QString &chanid)
hdhomerun_device_selector_t * m_deviceSelector
bool IsConnected(void) const
static void Return(HDHRStreamHandler *&ref, int inputid)
QString TunerGet(const QString &name)
QString TunerSet(const QString &name, const QString &value)
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
void setObjectName(const QString &name)
QRecursiveMutex m_pidLock
StreamDataList m_streamDataList
void WriteMPTS(const unsigned char *buffer, uint len)
Write out a copy of the raw MPTS.
volatile bool m_runningDesired
bool RemoveAllPIDFilters(void)
void SetRunning(bool running, bool using_buffering, bool using_section_reader)
bool UpdateFiltersFromStreamData(void)
QRecursiveMutex m_listenerLock
static QString filt_str(uint pid)
@ hdhrTuneModeFrequencyPid
@ hdhrTuneModeFrequencyProgram
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
#define ENO
This can be appended to the LOG args with "+".
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
QDateTime current(bool stripped)
Returns current Date and Time in UTC.