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