MythTV  master
satipstreamhandler.cpp
Go to the documentation of this file.
1 // -*- Mode: c++ -*-
2 
3 // C++ headers
4 #include <chrono>
5 #include <thread>
6 
7 // Qt headers
8 #include <QString>
9 #include <QMap>
10 #include <QMutex>
11 #include <QMutexLocker>
12 
13 // MythTV headers
15 
16 #include "cardutil.h"
17 #include "dtvsignalmonitor.h"
18 #include "mpeg/mpegstreamdata.h"
19 #include "mpeg/streamlisteners.h"
20 #include "satipchannel.h"
21 #include "satipstreamhandler.h"
22 #include "satiputils.h"
23 
24 #define LOC QString("SatIPSH[%1]: ").arg(m_inputId)
25 
26 // For implementing Get & Return
27 QMap<QString, SatIPStreamHandler*> SatIPStreamHandler::s_handlers;
28 QMap<QString, uint> SatIPStreamHandler::s_handlersRefCnt;
30 
31 SatIPStreamHandler *SatIPStreamHandler::Get(const QString &devname, int inputid)
32 {
33  QMutexLocker locker(&s_handlersLock);
34 
35  QMap<QString, SatIPStreamHandler*>::iterator it = s_handlers.find(devname);
36 
37  if (it == s_handlers.end())
38  {
39  auto *newhandler = new SatIPStreamHandler(devname, inputid);
40  newhandler->Open();
41  s_handlers[devname] = newhandler;
42  s_handlersRefCnt[devname] = 1;
43 
44  LOG(VB_RECORD, LOG_INFO,
45  QString("SatIPSH[%1]: Creating new stream handler for %2")
46  .arg(inputid).arg(devname));
47  }
48  else
49  {
50  s_handlersRefCnt[devname]++;
51  uint rcount = s_handlersRefCnt[devname];
52  (*it)->m_inputId = inputid;
53 
54  LOG(VB_RECORD, LOG_INFO,
55  QString("SatIPSH[%1]: Using existing stream handler for %2").arg(inputid).arg(devname) +
56  QString(" (%1 users)").arg(rcount));
57  }
58 
59  return s_handlers[devname];
60 }
61 
63 {
64  QMutexLocker locker(&s_handlersLock);
65 
66  QString devname = ref->m_device;
67 
68  QMap<QString, uint>::iterator rit = s_handlersRefCnt.find(devname);
69  if (rit == s_handlersRefCnt.end())
70  {
71  LOG(VB_RECORD, LOG_ERR, QString("SatIPSH[%1]: Return(%2) not found")
72  .arg(inputid).arg(devname));
73  return;
74  }
75 
76  LOG(VB_RECORD, LOG_INFO, QString("SatIPSH[%1]: Return stream handler for %2 (%3 users)")
77  .arg(inputid).arg(devname).arg(*rit));
78 
79  if (*rit > 1)
80  {
81  ref = nullptr;
82  (*rit)--;
83  return;
84  }
85 
86  QMap<QString, SatIPStreamHandler*>::iterator it = s_handlers.find(devname);
87  if ((it != s_handlers.end()) && (*it == ref))
88  {
89  LOG(VB_RECORD, LOG_INFO, QString("SatIPSH[%1]: Closing handler for %2")
90  .arg(inputid).arg(devname));
91  (*it)->Stop();
92  (*it)->Close();
93  delete *it;
94  s_handlers.erase(it);
95  }
96  else
97  {
98  LOG(VB_GENERAL, LOG_ERR,
99  QString("SatIPSH[%1] Error: Couldn't find handler for %2")
100  .arg(inputid).arg(devname));
101  }
102 
103  s_handlersRefCnt.erase(rit);
104  ref = nullptr;
105 }
106 
107 SatIPStreamHandler::SatIPStreamHandler(const QString &device, int inputid)
108  : StreamHandler(device, inputid)
109  , m_inputId(inputid)
110  , m_device(device)
111  , m_rtsp(new SatIPRTSP(this))
112 {
113  setObjectName("SatIPStreamHandler");
114 
115  LOG(VB_RECORD, LOG_DEBUG, LOC +
116  QString("ctor for %2").arg(device));
117 }
118 
120 {
121 #ifdef DEBUG_PID_FILTERS
122  LOG(VB_RECORD, LOG_DEBUG, LOC + "UpdateFilters()");
123 #endif // DEBUG_PID_FILTERS
124  QMutexLocker locker(&m_pidLock);
125 
126  QStringList pids;
127 
128  if (m_pidInfo.contains(0x2000))
129  {
130  pids.append("all");
131  }
132  else
133  {
134  for (auto it = m_pidInfo.cbegin(); it != m_pidInfo.cend(); ++it)
135  pids.append(QString("%1").arg(it.key()));
136  }
137 #ifdef DEBUG_PID_FILTERS
138  QString msg = QString("PIDS: '%1'").arg(pids.join(","));
139  LOG(VB_RECORD, LOG_DEBUG, LOC + msg);
140 #endif // DEBUG_PID_FILTERS
141 
142  bool rval = true;
143  if (m_rtsp && m_oldpids != pids)
144  {
145  rval = m_rtsp->Play(pids);
146  m_oldpids = pids;
147  }
148 
149  return rval;
150 }
151 
153 {
154  RunProlog();
155 
156  SetRunning(true, false, false);
157 
158  LOG(VB_RECORD, LOG_INFO, LOC + "RunTS(): begin");
159 
160  QElapsedTimer last_update;
161 
162  while (m_runningDesired && !m_bError)
163  {
164  {
165  QMutexLocker locker(&m_tunelock);
166 
168  {
169  if (m_setupinvoked)
170  {
171  m_rtsp->Teardown();
172  m_setupinvoked = false;
173  }
174 
175  if (m_rtsp->Setup(m_tuningurl))
176  {
178  m_setupinvoked = true;
179  }
180 
181  last_update.restart();
182  }
183  }
184 
185  // Update the PID filters every 100 milliseconds
186  auto elapsed = !last_update.isValid()
187  ? -1ms : std::chrono::milliseconds(last_update.elapsed());
188  elapsed = (elapsed < 0ms) ? 1s : elapsed;
189  if (elapsed > 100ms)
190  {
192  UpdateFilters();
193  last_update.restart();
194  }
195 
196  // Delay to avoid busy wait loop
197  std::this_thread::sleep_for(20ms);
198 
199  }
200  LOG(VB_RECORD, LOG_INFO, LOC + "RunTS(): " + "shutdown");
201 
203 
204  // TEARDOWN command
205  if (m_setupinvoked)
206  {
207  QMutexLocker locker(&m_tunelock);
208  m_rtsp->Teardown();
209  m_setupinvoked = false;
210  m_oldtuningurl = "";
211  }
212 
213  LOG(VB_RECORD, LOG_INFO, LOC + "RunTS(): end");
214  SetRunning(false, false, false);
215  RunEpilog();
216 }
217 
219 {
220  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Tune %1").arg(tuning.m_frequency));
221 
222  QMutexLocker locker(&m_tunelock);
223 
224  // Build the query string
225  QStringList qry;
226 
228  {
229  qry.append(QString("fe=%1").arg(m_frontend+1));
230  qry.append(QString("freq=%1").arg(SatIP::freq(tuning.m_frequency)));
231  qry.append(QString("sr=%1").arg(tuning.m_symbolRate / 1000)); // symbolrate in ksymb/s
232  qry.append("msys=dvbc");
233  qry.append(QString("mtype=%1").arg(SatIP::mtype(tuning.m_modulation)));
234  }
236  {
237  qry.append(QString("fe=%1").arg(m_frontend+1));
238  qry.append(QString("freq=%1").arg(SatIP::freq(tuning.m_frequency)));
239  qry.append(QString("bw=%1").arg(SatIP::bw(tuning.m_bandwidth)));
240  qry.append(QString("msys=%1").arg(SatIP::msys(tuning.m_modSys)));
241  qry.append(QString("tmode=%1").arg(SatIP::tmode(tuning.m_transMode)));
242  qry.append(QString("mtype=%1").arg(SatIP::mtype(tuning.m_modulation)));
243  qry.append(QString("gi=%1").arg(SatIP::gi(tuning.m_guardInterval)));
244  qry.append(QString("fec=%1").arg(SatIP::fec(tuning.m_fec)));
245  }
247  {
248  qry.append(QString("fe=%1").arg(m_frontend+1));
249  qry.append(QString("freq=%1").arg(SatIP::freq(tuning.m_frequency*1000))); // frequency in Hz
250  qry.append(QString("pol=%1").arg(SatIP::pol(tuning.m_polarity)));
251  qry.append(QString("ro=%1").arg(SatIP::ro(tuning.m_rolloff)));
252  qry.append(QString("msys=%1").arg(SatIP::msys(tuning.m_modSys)));
253  qry.append(QString("mtype=%1").arg(SatIP::mtype(tuning.m_modulation)));
254  qry.append(QString("sr=%1").arg(tuning.m_symbolRate / 1000)); // symbolrate in ksymb/s
255  qry.append(QString("fec=%1").arg(SatIP::fec(tuning.m_fec)));
256  qry.append(QString("plts=auto")); // pilot tones
257  }
258  else
259  {
260  LOG(VB_RECORD, LOG_ERR, LOC + QString("Unhandled m_tunerType %1 %2").arg(m_tunerType).arg(m_tunerType.toString()));
261  return false;
262  }
263 
264  QUrl url = QUrl(m_baseurl);
265  url.setQuery(qry.join("&"));
266 
267  m_tuningurl = url;
268 
269  LOG(VB_RECORD, LOG_INFO, LOC + QString("Tune url:%1").arg(url.toString()));
270 
272  {
273  LOG(VB_RECORD, LOG_INFO, LOC + QString("Skip tuning, already tuned to this url"));
274  return true;
275  }
276 
277  // Need SETUP and PLAY (with pids=none) to get RTSP packets with tuner lock info
278  if (m_rtsp)
279  {
280  bool rval = true;
281 
282  // TEARDOWN command
283  if (m_setupinvoked)
284  {
285  rval = m_rtsp->Teardown();
286  m_setupinvoked = false;
287  }
288 
289  // SETUP command
290  if (rval)
291  {
292  rval = m_rtsp->Setup(m_tuningurl);
293  }
294  if (rval)
295  {
297  m_setupinvoked = true;
298  }
299 
300  // PLAY command
301  if (rval)
302  {
303  QStringList pids;
304  m_rtsp->Play(pids);
305  m_oldpids = pids;
306  }
307  return rval;
308  }
309  return true;
310 }
311 
313 {
314  QUrl url;
315  url.setScheme("rtsp");
316  url.setPort(554);
317  url.setPath("/");
318 
319  // Discover the device using SSDP
320  QStringList devinfo = m_device.split(":");
321  if (devinfo.value(0).toUpper() == "UUID")
322  {
323  QString deviceId = QString("uuid:%1").arg(devinfo.value(1));
324  m_frontend = devinfo.value(3).toUInt();
325 
326  QString ip = SatIP::findDeviceIP(deviceId);
327  if (ip != nullptr)
328  {
329  LOG(VB_RECORD, LOG_INFO, LOC + QString("Discovered device %1 at %2").arg(deviceId, ip));
330  }
331  else
332  {
333  LOG(VB_RECORD, LOG_ERR, LOC + QString("Failed to discover device %1, no IP found").arg(deviceId));
334  return false;
335  }
336 
337  url.setHost(ip);
338  }
339  else
340  {
341  // TODO: Handling of manual IP devices
342  }
343 
345  m_baseurl = url;
346 
347  return true;
348 }
349 
351 {
352  delete m_rtsp;
353  m_rtsp = nullptr;
354  m_baseurl = nullptr;
355 }
DTVMultiplex::m_frequency
uint64_t m_frequency
Definition: dtvmultiplex.h:94
DTVMultiplex
Definition: dtvmultiplex.h:24
SatIPRTSP::Setup
bool Setup(const QUrl &url)
Definition: satiprtsp.cpp:111
DTVTunerType::kTunerTypeDVBC
static const int kTunerTypeDVBC
Definition: dtvconfparserhelpers.h:95
DTVMultiplex::m_rolloff
DTVRollOff m_rolloff
Definition: dtvmultiplex.h:107
StreamHandler::RemoveAllPIDFilters
bool RemoveAllPIDFilters(void)
Definition: streamhandler.cpp:240
SatIPRTSP::Play
bool Play(QStringList &pids)
Definition: satiprtsp.cpp:187
StreamHandler::SetRunning
void SetRunning(bool running, bool using_buffering, bool using_section_reader)
Definition: streamhandler.cpp:173
SatIP::ro
static QString ro(DTVRollOff ro)
Definition: satiputils.cpp:439
StreamHandler
Definition: streamhandler.h:58
SatIPStreamHandler::m_tuningurl
QUrl m_tuningurl
Definition: satipstreamhandler.h:70
DTVTunerType::kTunerTypeDVBS1
static const int kTunerTypeDVBS1
Definition: dtvconfparserhelpers.h:93
SatIP::bw
static QString bw(DTVBandwidth bw)
Definition: satiputils.cpp:235
MThread::setObjectName
void setObjectName(const QString &name)
Definition: mthread.cpp:238
SatIPStreamHandler::m_rtsp
SatIPRTSP * m_rtsp
Definition: satipstreamhandler.h:81
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
SatIP::tmode
static QString tmode(DTVTransmitMode tmode)
Definition: satiputils.cpp:332
DTVMultiplex::m_bandwidth
DTVBandwidth m_bandwidth
Definition: dtvmultiplex.h:97
SatIPStreamHandler::m_oldtuningurl
QUrl m_oldtuningurl
Definition: satipstreamhandler.h:71
streamlisteners.h
satipchannel.h
SatIPStreamHandler::s_handlersRefCnt
static QMap< QString, uint > s_handlersRefCnt
Definition: satipstreamhandler.h:59
SatIP::findDeviceIP
static QString findDeviceIP(const QString &deviceuuid)
Definition: satiputils.cpp:152
satiputils.h
StreamHandler::m_pidInfo
PIDInfoMap m_pidInfo
Definition: streamhandler.h:139
mythlogging.h
StreamHandler::m_pidLock
QRecursiveMutex m_pidLock
Definition: streamhandler.h:136
SatIPStreamHandler::Return
static void Return(SatIPStreamHandler *&ref, int inputid)
Definition: satipstreamhandler.cpp:62
DTVMultiplex::m_guardInterval
DTVGuardInterval m_guardInterval
Definition: dtvmultiplex.h:102
SatIPStreamHandler::Open
bool Open(void)
Definition: satipstreamhandler.cpp:312
SatIP::toTunerType
static int toTunerType(const QString &deviceid)
Definition: satiputils.cpp:201
StreamHandler::UpdateFiltersFromStreamData
bool UpdateFiltersFromStreamData(void)
Definition: streamhandler.cpp:290
DTVTunerType::toString
QString toString() const
Definition: dtvconfparserhelpers.h:154
SatIPStreamHandler::m_tunerType
DTVTunerType m_tunerType
Definition: satipstreamhandler.h:66
MThread::RunEpilog
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:209
SatIP::freq
static QString freq(uint64_t freq)
Definition: satiputils.cpp:268
DTVMultiplex::m_modSys
DTVModulationSystem m_modSys
Definition: dtvmultiplex.h:106
SatIP::gi
static QString gi(DTVGuardInterval gi)
Definition: satiputils.cpp:361
DTVMultiplex::m_fec
DTVCodeRate m_fec
Definition: dtvmultiplex.h:105
SatIPStreamHandler::SatIPStreamHandler
SatIPStreamHandler(const QString &device, int inputid)
Definition: satipstreamhandler.cpp:107
SatIPRTSP::Teardown
bool Teardown()
Definition: satiprtsp.cpp:221
uint
unsigned int uint
Definition: compat.h:79
SatIP::pol
static QString pol(DTVPolarity pol)
Definition: satiputils.cpp:460
LOC
#define LOC
Definition: satipstreamhandler.cpp:24
mpegstreamdata.h
SatIPStreamHandler::Close
void Close(void)
Definition: satipstreamhandler.cpp:350
DTVTunerType::kTunerTypeDVBS2
static const int kTunerTypeDVBS2
Definition: dtvconfparserhelpers.h:94
DTVMultiplex::m_symbolRate
uint64_t m_symbolRate
Definition: dtvmultiplex.h:95
SatIPStreamHandler::m_baseurl
QUrl m_baseurl
Definition: satipstreamhandler.h:69
SatIPStreamHandler::UpdateFilters
bool UpdateFilters() override
Definition: satipstreamhandler.cpp:119
cardutil.h
StreamHandler::m_runningDesired
volatile bool m_runningDesired
Definition: streamhandler.h:121
SatIPStreamHandler::s_handlersLock
static QMutex s_handlersLock
Definition: satipstreamhandler.h:60
SatIPStreamHandler::run
void run(void) override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: satipstreamhandler.cpp:152
SatIPRTSP
Definition: satiprtsp.h:94
satipstreamhandler.h
SatIPStreamHandler::Get
static SatIPStreamHandler * Get(const QString &devname, int inputid)
Definition: satipstreamhandler.cpp:31
SatIPStreamHandler::m_setupinvoked
bool m_setupinvoked
Definition: satipstreamhandler.h:72
SatIP::fec
static QString fec(DTVCodeRate fec)
Definition: satiputils.cpp:394
StreamHandler::m_bError
volatile bool m_bError
Definition: streamhandler.h:126
DTVMultiplex::m_modulation
DTVModulation m_modulation
Definition: dtvmultiplex.h:100
DTVMultiplex::m_polarity
DTVPolarity m_polarity
Definition: dtvmultiplex.h:104
SatIPStreamHandler::m_tunelock
QRecursiveMutex m_tunelock
Definition: satipstreamhandler.h:76
DTVTunerType::kTunerTypeDVBT
static const int kTunerTypeDVBT
Definition: dtvconfparserhelpers.h:96
SatIP::msys
static QString msys(DTVModulationSystem msys)
Definition: satiputils.cpp:273
DTVTunerType::kTunerTypeDVBT2
static const int kTunerTypeDVBT2
Definition: dtvconfparserhelpers.h:97
SatIPStreamHandler::Tune
bool Tune(const DTVMultiplex &tuning)
Definition: satipstreamhandler.cpp:218
SatIPStreamHandler::s_handlers
static QMap< QString, SatIPStreamHandler * > s_handlers
Definition: satipstreamhandler.h:58
SatIP::mtype
static QString mtype(DTVModulation mtype)
Definition: satiputils.cpp:299
dtvsignalmonitor.h
SatIPStreamHandler::m_device
QString m_device
Definition: satipstreamhandler.h:67
DTVMultiplex::m_transMode
DTVTransmitMode m_transMode
Definition: dtvmultiplex.h:101
SatIPStreamHandler
Definition: satipstreamhandler.h:28
SatIPStreamHandler::m_oldpids
QStringList m_oldpids
Definition: satipstreamhandler.h:78
SatIPStreamHandler::m_frontend
uint m_frontend
Definition: satipstreamhandler.h:68