8 #include <QRegularExpression>
11 #include <QStringList>
12 #include <QDomDocument>
14 #ifdef USING_HDHOMERUN
15 #include HDHOMERUN_HEADERFILE
27 #define LOC QString("HDHRChanFetch: ")
32 {
"http://{IP}/lineup.xml?tuning" };
36 for (QDomNode dname = element.firstChild(); !dname.isNull();
37 dname = dname.nextSibling())
39 QDomText
t = dname.toText();
46 QString
getStrValue(
const QDomElement &element,
const QString &name,
int index=0)
48 QDomNodeList nodes = element.elementsByTagName(name);
51 if (index >= nodes.count())
53 QDomElement e = nodes.at(index).toElement();
59 int getIntValue(
const QDomElement &element,
const QString &name,
int index=0)
65 bool sendQuery(
const QString& query, QDomDocument* xmlDoc)
72 #if QT_VERSION < QT_VERSION_CHECK(6,5,0)
77 if (!xmlDoc->setContent(result,
false, &errorMsg, &errorLine, &errorColumn))
79 LOG(VB_GENERAL, LOG_ERR,
LOC +
80 QString(
"Error parsing: %1\nat line: %2 column: %3 msg: %4").
81 arg(query).arg(errorLine).arg(errorColumn).arg(errorMsg));
85 auto parseResult = xmlDoc->setContent(result);
88 LOG(VB_GENERAL, LOG_ERR,
LOC +
89 QString(
"Error parsing: %1\nat line: %2 column: %3 msg: %4").
90 arg(query).arg(parseResult.errorLine).arg(parseResult.errorColumn)
91 .arg(parseResult.errorMessage));
97 QDomNodeList statusNodes = xmlDoc->elementsByTagName(
"Status");
99 if (!statusNodes.count())
100 statusNodes = xmlDoc->elementsByTagName(
"Error");
102 if (statusNodes.count())
104 QDomElement elem = statusNodes.at(0).toElement();
108 QString errorDesc =
getStrValue(elem,
"ErrorDescription");
113 LOG(VB_GENERAL, LOG_ERR,
LOC +
114 QString(
"API Error: %1 - %2, Query was: %3").arg(errorCode).arg(errorDesc, query));
127 auto *xmlDoc =
new QDomDocument();
130 query.replace(
"{IP}", ip);
139 QDomNodeList chanNodes = xmlDoc->elementsByTagName(
"Program");
141 for (
int x = 0; x < chanNodes.count(); x++)
143 QDomElement chanElem = chanNodes.at(x).toElement();
144 QString guideName =
getStrValue(chanElem,
"GuideName");
145 QString guideNumber =
getStrValue(chanElem,
"GuideNumber");
147 QString modulation =
getStrValue(chanElem,
"Modulation");
148 QString videoCodec =
getStrValue(chanElem,
"VideoCodec");
149 QString audioCodec =
getStrValue(chanElem,
"AudioCodec");
152 uint transportID =
getStrValue(chanElem,
"TransportStreamID").toUInt();
153 QString onid =
getStrValue(chanElem,
"OriginalNetworkID");
158 onid.replace(
":",
"");
159 uint originalNetworkID = onid.toUInt();
161 LOG(VB_CHANSCAN, LOG_DEBUG,
LOC + QString(
"ONID/TID/SID %1 %2 %3")
162 .arg(originalNetworkID).arg(transportID).arg(serviceID));
164 HDHRChannelInfo chanInfo(guideName, guideNumber, url, modulation, videoCodec,
165 audioCodec, frequency, serviceID, originalNetworkID, transportID);
167 result->insert(guideNumber, chanInfo);
174 #ifdef USING_HDHOMERUN
175 hdhomerun_device_t *hdhr =
176 hdhomerun_device_create_from_str(device.toLatin1(),
nullptr);
180 uint32_t ipv4 = hdhomerun_device_get_device_ip(hdhr);
181 hdhomerun_device_destroy(hdhr);
186 return QString(
"%1.%2.%3.%4").arg(ipv4>>24&0xff).arg(ipv4>>16&0xff).arg(ipv4>>8&0xff).arg(ipv4&0xff);
195 if (hdhrmod.contains(
"dvbt2"))
197 if (hdhrmod.contains(
"dvbt"))
199 if (hdhrmod.startsWith(
"a8qam"))
201 if (hdhrmod.contains(
"vsb"))
203 if (hdhrmod.contains(
"psk"))
210 if (hdhrmod.startsWith(
"t8") || hdhrmod.startsWith(
"a8"))
212 if (hdhrmod.startsWith(
"t7") || hdhrmod.startsWith(
"a7"))
214 if (hdhrmod.startsWith(
"t6") || hdhrmod.startsWith(
"a6"))
221 static const QRegularExpression re(R
"(^(a8qam\d+-)(\d+))");
222 QRegularExpressionMatch match = re.match(hdhrmod);
223 if (match.hasMatch())
225 QString matched = match.captured(2);
226 return matched.toUInt() * 1000;
233 if (hdhrmod.contains(
"qam256"))
235 if (hdhrmod.contains(
"qam128"))
237 if (hdhrmod.contains(
"qam64"))
239 if (hdhrmod.contains(
"qam16"))
241 if (hdhrmod.contains(
"qpsk"))
243 if (hdhrmod.contains(
"8vsb"))
250 if (channum.contains(
"."))
253 QTextStream(&channum) >> atsc_major_channel >> dot >> atsc_minor_channel;
261 m_scanMonitor(monitor),
263 m_inputName(std::move(inputname)),
264 m_sourceId(sourceid),
265 m_serviceType(serviceType),
266 m_thread(new
MThread(
"HDHRChannelFetcher", this))
268 LOG(VB_CHANSCAN, LOG_INFO,
LOC + QString(
"Has ScanMonitor %1")
269 .arg(monitor?
"true":
"false"));
306 LOG(VB_CHANSCAN, LOG_INFO,
LOC + QString(
"Found %1 channels")
332 LOG(VB_CHANNEL, LOG_INFO,
LOC +
333 QString(
"Failed to get IP address from videodev (%1)").arg(dev));
334 QMutexLocker locker(&
m_lock);
339 LOG(VB_CHANNEL, LOG_INFO,
LOC + QString(
"HDHomeRun IP: %1").arg(ip));
359 QMutexLocker locker(&
m_lock);
372 LOG(VB_CHANSCAN, LOG_INFO,
LOC + QString(
"Found %1 channels").arg(
m_channels->size()));
375 hdhr_chan_map_t::const_iterator it =
m_channels->cbegin();
378 const QString& channum = it.key();
379 QString name = (*it).m_name;
380 uint serviceID = (*it).m_serviceID;
381 QString channelType = (*it).m_channelType;
382 QString hdhrmod = (*it).m_modulation;
383 uint networkID = (*it).m_networkID;
384 uint transportID = (*it).m_transportID;
385 uint frequency = (*it).m_frequency;
391 uint atsc_major_channel = 0;
392 uint atsc_minor_channel = 0;
394 QString sistandard = (atsc_major_channel > 0 && atsc_minor_channel > 0) ?
"atsc" :
"dvb";
396 bool use_on_air_guide =
true;
398 QString msg = tr(
"%1 channel %2: %3").arg(channelType).arg(channum, -5, QChar(
' ')).arg(name, -15, QChar(
' '));
399 LOG(VB_CHANSCAN, LOG_INFO, QString(
"Found %1").arg(msg));
421 bool adding_channel = chanid <= 0;
453 transportID, networkID, symbolrate, bandwidth,
454 'v',
'a',
'a', QString(), QString(),
'a', QString(),
455 QString(), QString(), modsys.
toString(),
"0.35");
458 LOG(VB_GENERAL, LOG_ERR, QString(
"No multiplex for %1 sid:%2 freq:%3 url:%4")
459 .arg(msg).arg(serviceID, -5, 10, QChar(
' ')).arg(frequency).arg((*it).m_tuning.GetDataURL().toString()));
467 channum, serviceID, atsc_major_channel, atsc_minor_channel,
469 QString(),
"Default", QString());
476 channum, serviceID, atsc_major_channel, atsc_minor_channel,
478 QString(),
"Default", QString());
482 LOG(VB_GENERAL, LOG_INFO, QString(
"%1 sid:%2 freq:%3 url:%4")
483 .arg(msg).arg(serviceID, -5, 10, QChar(
' ')).arg(frequency).arg((*it).m_tuning.GetDataURL().toString()));
495 QMutexLocker locker(&
m_lock);
503 uint range = 100 - minval;