1 #include "libmythbase/mythconfig.h"
10 #include <QRegularExpression>
11 #include <QTextStream>
13 #include <QStringList>
14 #include <QDomDocument>
17 #include HDHOMERUN_HEADERFILE
28 #define LOC QString("HDHRChanFetch: ")
33 {
"http://{IP}/lineup.xml?tuning" };
37 for (QDomNode dname = element.firstChild(); !dname.isNull();
38 dname = dname.nextSibling())
40 QDomText
t = dname.toText();
47 QString
getStrValue(
const QDomElement &element,
const QString &name,
int index=0)
49 QDomNodeList nodes = element.elementsByTagName(name);
52 if (index >= nodes.count())
54 QDomElement e = nodes.at(index).toElement();
60 int getIntValue(
const QDomElement &element,
const QString &name,
int index=0)
66 bool sendQuery(
const QString& query, QDomDocument* xmlDoc)
73 #if QT_VERSION < QT_VERSION_CHECK(6,5,0)
78 if (!xmlDoc->setContent(result,
false, &errorMsg, &errorLine, &errorColumn))
80 LOG(VB_GENERAL, LOG_ERR,
LOC +
81 QString(
"Error parsing: %1\nat line: %2 column: %3 msg: %4").
82 arg(query).arg(errorLine).arg(errorColumn).arg(errorMsg));
86 auto parseResult = xmlDoc->setContent(result);
89 LOG(VB_GENERAL, LOG_ERR,
LOC +
90 QString(
"Error parsing: %1\nat line: %2 column: %3 msg: %4").
91 arg(query).arg(parseResult.errorLine).arg(parseResult.errorColumn)
92 .arg(parseResult.errorMessage));
98 QDomNodeList statusNodes = xmlDoc->elementsByTagName(
"Status");
100 if (!statusNodes.count())
101 statusNodes = xmlDoc->elementsByTagName(
"Error");
103 if (statusNodes.count())
105 QDomElement elem = statusNodes.at(0).toElement();
109 QString errorDesc =
getStrValue(elem,
"ErrorDescription");
114 LOG(VB_GENERAL, LOG_ERR,
LOC +
115 QString(
"API Error: %1 - %2, Query was: %3").arg(errorCode).arg(errorDesc, query));
128 auto *xmlDoc =
new QDomDocument();
131 query.replace(
"{IP}", ip);
140 QDomNodeList chanNodes = xmlDoc->elementsByTagName(
"Program");
142 for (
int x = 0; x < chanNodes.count(); x++)
144 QDomElement chanElem = chanNodes.at(x).toElement();
145 QString guideName =
getStrValue(chanElem,
"GuideName");
146 QString guideNumber =
getStrValue(chanElem,
"GuideNumber");
148 QString modulation =
getStrValue(chanElem,
"Modulation");
149 QString videoCodec =
getStrValue(chanElem,
"VideoCodec");
150 QString audioCodec =
getStrValue(chanElem,
"AudioCodec");
153 uint transportID =
getStrValue(chanElem,
"TransportStreamID").toUInt();
154 QString onid =
getStrValue(chanElem,
"OriginalNetworkID");
159 onid.replace(
":",
"");
160 uint originalNetworkID = onid.toUInt();
162 LOG(VB_CHANSCAN, LOG_DEBUG,
LOC + QString(
"ONID/TID/SID %1 %2 %3")
163 .arg(originalNetworkID).arg(transportID).arg(serviceID));
165 HDHRChannelInfo chanInfo(guideName, guideNumber, url, modulation, videoCodec,
166 audioCodec, frequency, serviceID, originalNetworkID, transportID);
168 result->insert(guideNumber, chanInfo);
177 hdhomerun_device_create_from_str(device.toLatin1(),
nullptr);
181 uint32_t ipv4 = hdhomerun_device_get_device_ip(hdhr);
182 hdhomerun_device_destroy(hdhr);
187 return QString(
"%1.%2.%3.%4").arg(ipv4>>24&0xff).arg(ipv4>>16&0xff).arg(ipv4>>8&0xff).arg(ipv4&0xff);
196 if (hdhrmod.contains(
"dvbt2"))
198 if (hdhrmod.contains(
"dvbt"))
200 if (hdhrmod.startsWith(
"a8qam"))
202 if (hdhrmod.contains(
"vsb"))
204 if (hdhrmod.contains(
"psk"))
211 if (hdhrmod.startsWith(
"t8") || hdhrmod.startsWith(
"a8"))
213 if (hdhrmod.startsWith(
"t7") || hdhrmod.startsWith(
"a7"))
215 if (hdhrmod.startsWith(
"t6") || hdhrmod.startsWith(
"a6"))
222 static const QRegularExpression re(R
"(^(a8qam\d+-)(\d+))");
223 QRegularExpressionMatch match = re.match(hdhrmod);
224 if (match.hasMatch())
226 QString matched = match.captured(2);
227 return matched.toUInt() * 1000;
234 if (hdhrmod.contains(
"qam256"))
236 if (hdhrmod.contains(
"qam128"))
238 if (hdhrmod.contains(
"qam64"))
240 if (hdhrmod.contains(
"qam16"))
242 if (hdhrmod.contains(
"qpsk"))
244 if (hdhrmod.contains(
"8vsb"))
251 if (channum.contains(
"."))
254 QTextStream(&channum) >> atsc_major_channel >> dot >> atsc_minor_channel;
262 m_scanMonitor(monitor),
264 m_inputName(std::move(inputname)),
265 m_sourceId(sourceid),
266 m_serviceType(serviceType),
267 m_thread(new
MThread(
"HDHRChannelFetcher", this))
269 LOG(VB_CHANSCAN, LOG_INFO,
LOC + QString(
"Has ScanMonitor %1")
270 .arg(monitor?
"true":
"false"));
307 LOG(VB_CHANSCAN, LOG_INFO,
LOC + QString(
"Found %1 channels")
333 LOG(VB_CHANNEL, LOG_INFO,
LOC +
334 QString(
"Failed to get IP address from videodev (%1)").arg(dev));
335 QMutexLocker locker(&
m_lock);
340 LOG(VB_CHANNEL, LOG_INFO,
LOC + QString(
"HDHomeRun IP: %1").arg(ip));
360 QMutexLocker locker(&
m_lock);
373 LOG(VB_CHANSCAN, LOG_INFO,
LOC + QString(
"Found %1 channels").arg(
m_channels->size()));
376 hdhr_chan_map_t::const_iterator it =
m_channels->cbegin();
379 const QString& channum = it.key();
380 QString name = (*it).m_name;
381 uint serviceID = (*it).m_serviceID;
382 QString channelType = (*it).m_channelType;
383 QString hdhrmod = (*it).m_modulation;
384 uint networkID = (*it).m_networkID;
385 uint transportID = (*it).m_transportID;
386 uint frequency = (*it).m_frequency;
392 uint atsc_major_channel = 0;
393 uint atsc_minor_channel = 0;
395 QString sistandard = (atsc_major_channel > 0 && atsc_minor_channel > 0) ?
"atsc" :
"dvb";
397 bool use_on_air_guide =
true;
399 QString msg = tr(
"%1 channel %2: %3").arg(channelType).arg(channum, -5, QChar(
' ')).arg(name, -15, QChar(
' '));
400 LOG(VB_CHANSCAN, LOG_INFO, QString(
"Found %1").arg(msg));
422 bool adding_channel = chanid <= 0;
454 transportID, networkID, symbolrate, bandwidth,
455 'v',
'a',
'a', QString(), QString(),
'a', QString(),
456 QString(), QString(), modsys.
toString(),
"0.35");
459 LOG(VB_GENERAL, LOG_ERR, QString(
"No multiplex for %1 sid:%2 freq:%3 url:%4")
460 .arg(msg).arg(serviceID, -5, 10, QChar(
' ')).arg(frequency).arg((*it).m_tuning.GetDataURL().toString()));
468 channum, serviceID, atsc_major_channel, atsc_minor_channel,
470 QString(),
"Default", QString());
477 channum, serviceID, atsc_major_channel, atsc_minor_channel,
479 QString(),
"Default", QString());
483 LOG(VB_GENERAL, LOG_INFO, QString(
"%1 sid:%2 freq:%3 url:%4")
484 .arg(msg).arg(serviceID, -5, 10, QChar(
' ')).arg(frequency).arg((*it).m_tuning.GetDataURL().toString()));
496 QMutexLocker locker(&
m_lock);
504 uint range = 100 - minval;