7 #include <sys/select.h>
22 #ifdef NEED_HDHOMERUN_DEVICE_SELECTOR_LOAD_FROM_STR
23 static int hdhomerun_device_selector_load_from_str(
struct hdhomerun_device_selector_t *hds,
char *device_str);
26 #define LOC QString("HDHRSH[%1](%2): ").arg(m_inputId).arg(m_device)
33 int inputid,
int majorid)
37 QMap<int,HDHRStreamHandler*>::iterator it =
s_handlers.find(majorid);
46 LOG(VB_RECORD, LOG_INFO,
47 QString(
"HDHRSH[%1]: Creating new stream handler %2 for %3")
48 .arg(inputid).arg(majorid).arg(devname));
54 LOG(VB_RECORD, LOG_INFO,
55 QString(
"HDHRSH[%1]: Using existing stream handler %2 for %3")
56 .arg(inputid).arg(majorid)
57 .arg(devname) + QString(
" (%1 in use)").arg(rcount));
73 QMap<int,HDHRStreamHandler*>::iterator it =
s_handlers.find(majorid);
83 LOG(VB_RECORD, LOG_INFO, QString(
"HDHRSH[%1]: Closing handler for %2")
84 .arg(inputid).arg(majorid));
91 LOG(VB_GENERAL, LOG_ERR,
92 QString(
"HDHRSH[%1] Error: Couldn't find handler for %2")
93 .arg(inputid).arg(majorid));
121 LOG(VB_GENERAL, LOG_ERR,
LOC +
122 "Starting recording (set target failed). Aborting.");
132 LOG(VB_RECORD, LOG_INFO,
LOC +
"RunTS(): begin");
135 QElapsedTimer last_update;
138 auto elapsed = !last_update.isValid()
139 ? -1ms : std::chrono::milliseconds(last_update.elapsed());
140 elapsed = (elapsed < 0ms) ? 1s : elapsed;
146 last_update.restart();
149 size_t read_size = VIDEO_DATA_BUFFER_SIZE_1S / 8;
150 read_size /= VIDEO_DATA_PACKET_SIZE;
151 read_size *= VIDEO_DATA_PACKET_SIZE;
153 size_t data_length = 0;
154 unsigned char *data_buffer = hdhomerun_device_stream_recv(
159 std::this_thread::sleep_for(20ms);
174 remainder = sit.key()->ProcessData(data_buffer, data_length);
176 WriteMPTS(data_buffer, data_length - remainder);
181 LOG(VB_RECORD, LOG_INFO,
LOC +
182 QString(
"RunTS(): data_length = %1 remainder = %2")
183 .arg(data_length).arg(remainder));
186 LOG(VB_RECORD, LOG_INFO,
LOC +
"RunTS(): " +
"shutdown");
197 struct hdhomerun_video_sock_t* vs =
nullptr;
198 struct hdhomerun_video_stats_t stats {};
202 hdhomerun_video_get_stats(vs, &stats);
203 LOG(VB_RECORD, LOG_INFO,
LOC +
204 QString(
"stream stats: packet_count=%1 "
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));
217 LOG(VB_RECORD, LOG_INFO,
LOC +
"RunTS(): " +
"end");
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);
242 LOG(VB_GENERAL, LOG_ERR,
LOC +
243 "UpdateFilters called in wrong tune mode");
247 #ifdef DEBUG_PID_FILTERS
248 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"UpdateFilters()");
249 #endif // DEBUG_PID_FILTERS
254 std::vector<uint> range_min;
255 std::vector<uint> range_max;
259 range_min.push_back(it.key());
260 PIDInfoMap::const_iterator eit = it;
262 (eit !=
m_pidInfo.cend()) && (it.key() + 1 == eit.key());
264 range_max.push_back(it.key());
266 if (range_min.size() > 16)
268 range_min.resize(16);
269 uint pid_max = range_max.back();
270 range_max.resize(15);
271 range_max.push_back(pid_max);
274 for (
size_t i = 0; i < range_min.size(); i++)
277 if (range_min[i] != range_max[i])
278 filter += QString(
"-%1").arg(
filt_str(range_max[i]));
282 filter = filter.trimmed();
284 QString new_filter =
TunerSet(
"filter", filter);
286 #ifdef DEBUG_PID_FILTERS
287 QString msg = QString(
"Filter: '%1'").arg(filter);
288 if (filter != new_filter)
289 msg += QString(
"\n\t\t\t\t'%2'").arg(new_filter);
291 LOG(VB_RECORD, LOG_DEBUG,
LOC + msg);
292 #endif // DEBUG_PID_FILTERS
294 return filter == new_filter;
303 if (QString(model).contains(
"cablecard", Qt::CaseInsensitive))
305 QString status_channel =
"none";
306 hdhomerun_tuner_status_t t_status {};
308 if (hdhomerun_device_get_oob_status(
311 LOG(VB_GENERAL, LOG_ERR,
LOC +
312 "Failed to query Cable card OOB channel");
316 status_channel = QString(t_status.channel);
317 LOG(VB_RECORD, LOG_INFO,
LOC +
318 QString(
"Cable card OOB channel is '%1'")
319 .arg(status_channel));
322 if (status_channel ==
"none")
324 LOG(VB_RECORD, LOG_INFO,
LOC +
"Cable card is not present");
329 LOG(VB_RECORD, LOG_INFO,
LOC +
"Cable card is present");
333 else if (QString(model).endsWith(
"dvbt", Qt::CaseInsensitive))
337 else if (QString(model).endsWith(
"dvbc", Qt::CaseInsensitive))
341 else if (QString(model).endsWith(
"dvbtc", Qt::CaseInsensitive))
376 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unable to create device selector");
380 QStringList devices =
m_device.split(
",");
381 for (
int i = 0; i < devices.size(); ++i)
383 QByteArray ba = devices[i].toUtf8();
384 int n = hdhomerun_device_selector_load_from_str(
386 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Added %1 devices from %3")
387 .arg(n).arg(devices[i]));
394 LOG(VB_GENERAL, LOG_ERR,
LOC +
395 QString(
"Unable to find a free device"));
403 LOG(VB_GENERAL, LOG_INFO,
LOC +
404 QString(
"Connected to device(%1)")
411 const QString &name,
bool report_error_return,
bool print_error)
const
417 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Get request failed (not connected)");
421 QString valname = QString(
"/tuner%1/%2").arg(
m_tuner).arg(name);
422 char *value =
nullptr;
423 char *
error =
nullptr;
424 if (hdhomerun_device_get_var(
428 LOG(VB_GENERAL, LOG_ERR,
LOC +
429 QString(
"Get %1 request failed").arg(valname) +
ENO);
433 if (report_error_return &&
error)
437 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"DeviceGet(%1): %2")
438 .arg(name).arg(
error));
444 return QString(value);
448 const QString &name,
const QString &val,
449 bool report_error_return,
bool print_error)
455 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Set request failed (not connected)");
460 QString valname = QString(
"/tuner%1/%2").arg(
m_tuner).arg(name);
461 char *value =
nullptr;
462 char *
error =
nullptr;
465 LOG(VB_CHANSCAN, LOG_DEBUG,
LOC + valname +
" " + val);
467 if (hdhomerun_device_set_var(
469 val.toLocal8Bit().constData(), &value, &
error) < 0)
471 LOG(VB_GENERAL, LOG_ERR,
LOC +
472 QString(
"Set %1 to '%2' request failed").arg(valname).arg(val) +
478 if (report_error_return &&
error)
483 if (!(val.contains(
"0x2000") && strstr(
error,
"ERROR: invalid pid filter")))
485 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"DeviceSet(%1 %2): %3")
486 .arg(name).arg(val).arg(
error));
493 return QString(value);
515 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"Not Re-Tuning channel %1")
520 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"Tuning channel %1 (was %2)")
522 return !
TunerSet(
"channel", chanid).isEmpty();
532 LOG(VB_GENERAL, LOG_ERR,
LOC +
"TuneProgram called in wrong tune mode");
536 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"Tuning program %1")
537 .arg(mpeg_prog_num));
539 "program", QString::number(mpeg_prog_num),
false).isEmpty();
549 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"Not Re-Tuning channel %1")
553 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"TuneVChannel(%1) from (%2)")
556 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"Tuning vchannel %1").arg(vchn));
557 return !
TunerSet(
"vchannel", vchn).isEmpty();
560 #ifdef NEED_HDHOMERUN_DEVICE_SELECTOR_LOAD_FROM_STR
566 struct hdhomerun_device_selector_t {
567 struct hdhomerun_device_t **hd_list;
569 struct hdhomerun_debug_t *dbg;
572 static int hdhomerun_device_selector_load_from_str_discover(
struct hdhomerun_device_selector_t *hds, uint32_t target_ip, uint32_t device_id)
574 struct hdhomerun_discover_device_t result;
575 int discover_count = hdhomerun_discover_find_devices_custom(target_ip, HDHOMERUN_DEVICE_TYPE_TUNER, device_id, &result, 1);
576 if (discover_count != 1) {
581 unsigned int tuner_index;
582 for (tuner_index = 0; tuner_index < result.tuner_count; tuner_index++) {
583 struct hdhomerun_device_t *hd = hdhomerun_device_create(result.device_id, result.ip_addr, tuner_index, hds->dbg);
588 hdhomerun_device_selector_add_device(hds, hd);
595 static int hdhomerun_device_selector_load_from_str(
struct hdhomerun_device_selector_t *hds,
char *device_str)
601 if (sscanf(device_str,
"%u.%u.%u.%u", &a[0], &a[1], &a[2], &a[3]) == 4) {
602 uint32_t ip_addr = (uint32_t)((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | (a[3] << 0));
608 if (sscanf(device_str,
"%u.%u.%u.%u-%u", &a[0], &a[1], &a[2], &a[3], &tuner) == 5) {
609 struct hdhomerun_device_t *hd = hdhomerun_device_create(HDHOMERUN_DEVICE_ID_WILDCARD, ip_addr, tuner, hds->dbg);
614 hdhomerun_device_selector_add_device(hds, hd);
621 return hdhomerun_device_selector_load_from_str_discover(hds, ip_addr, HDHOMERUN_DEVICE_ID_WILDCARD);
628 uint32_t device_id = (uint32_t)strtoul(device_str, &end, 16);
629 if ((end == device_str + 8) && hdhomerun_discover_validate_device_id(device_id)) {
634 unsigned int tuner = (
unsigned int)strtoul(end + 1,
NULL, 10);
635 struct hdhomerun_device_t *hd = hdhomerun_device_create(device_id, 0, tuner, hds->dbg);
640 hdhomerun_device_selector_add_device(hds, hd);
647 return hdhomerun_device_selector_load_from_str_discover(hds, 0, device_id);