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  auto elapsed = !last_update.isValid()
184  ? -1ms : std::chrono::milliseconds(last_update.elapsed());
185  elapsed = (elapsed < 0ms) ? 1s : elapsed;
186  if (elapsed > 100ms)
187  {
189  UpdateFilters();
190  last_update.restart();
191  }
192 
193  // Delay to avoid busy wait loop
194  std::this_thread::sleep_for(20ms);
195 
196  }
197  LOG(VB_RECORD, LOG_INFO, LOC + "RunTS(): " + "shutdown");
198 
200 
201  // TEARDOWN command
202  if (m_setupinvoked)
203  {
204  QMutexLocker locker(&m_tunelock);
205  m_rtsp->Teardown();
206  m_setupinvoked = false;
207  m_oldtuningurl = "";
208  }
209 
210  LOG(VB_RECORD, LOG_INFO, LOC + "RunTS(): end");
211  SetRunning(false, false, false);
212  RunEpilog();
213 }
214 
216 {
217  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Tune %1").arg(tuning.m_frequency));
218 
219  QMutexLocker locker(&m_tunelock);
220 
221  // Build the query string
222  QStringList qry;
223 
225  {
226  qry.append(QString("fe=%1").arg(m_frontend+1));
227  qry.append(QString("freq=%1").arg(SatIP::freq(tuning.m_frequency)));
228  qry.append(QString("sr=%1").arg(tuning.m_symbolRate / 1000)); // symbolrate in ksymb/s
229  qry.append("msys=dvbc");
230  qry.append(QString("mtype=%1").arg(SatIP::mtype(tuning.m_modulation)));
231  }
233  {
234  qry.append(QString("fe=%1").arg(m_frontend+1));
235  qry.append(QString("freq=%1").arg(SatIP::freq(tuning.m_frequency)));
236  qry.append(QString("bw=%1").arg(SatIP::bw(tuning.m_bandwidth)));
237  qry.append(QString("msys=%1").arg(SatIP::msys(tuning.m_modSys)));
238  qry.append(QString("tmode=%1").arg(SatIP::tmode(tuning.m_transMode)));
239  qry.append(QString("mtype=%1").arg(SatIP::mtype(tuning.m_modulation)));
240  qry.append(QString("gi=%1").arg(SatIP::gi(tuning.m_guardInterval)));
241  qry.append(QString("fec=%1").arg(SatIP::fec(tuning.m_fec)));
242  }
244  {
245  qry.append(QString("fe=%1").arg(m_frontend+1));
246  qry.append(QString("freq=%1").arg(SatIP::freq(tuning.m_frequency*1000))); // frequency in Hz
247  qry.append(QString("pol=%1").arg(SatIP::pol(tuning.m_polarity)));
248  qry.append(QString("ro=%1").arg(SatIP::ro(tuning.m_rolloff)));
249  qry.append(QString("msys=%1").arg(SatIP::msys(tuning.m_modSys)));
250  qry.append(QString("mtype=%1").arg(SatIP::mtype(tuning.m_modulation)));
251  qry.append(QString("sr=%1").arg(tuning.m_symbolRate / 1000)); // symbolrate in ksymb/s
252  qry.append(QString("fec=%1").arg(SatIP::fec(tuning.m_fec)));
253  qry.append(QString("plts=auto")); // pilot tones
254  }
255  else
256  {
257  LOG(VB_RECORD, LOG_ERR, LOC + QString("Unhandled m_tunerType %1 %2").arg(m_tunerType).arg(m_tunerType.toString()));
258  return false;
259  }
260 
261  QUrl url = QUrl(m_baseurl);
262  url.setQuery(qry.join("&"));
263 
264  m_tuningurl = url;
265 
266  LOG(VB_RECORD, LOG_INFO, LOC + QString("Tune url:%1").arg(url.toString()));
267 
269  {
270  LOG(VB_RECORD, LOG_INFO, LOC + QString("Skip tuning, already tuned to this url"));
271  return true;
272  }
273 
274  // Need SETUP and PLAY (with pids=none) to get RTSP packets with tuner lock info
275  if (m_rtsp)
276  {
277  bool rval = true;
278 
279  // TEARDOWN command
280  if (m_setupinvoked)
281  {
282  rval = m_rtsp->Teardown();
283  m_setupinvoked = false;
284  }
285 
286  // SETUP command
287  if (rval)
288  {
289  rval = m_rtsp->Setup(m_tuningurl);
291  m_setupinvoked = true;
292  }
293 
294  // PLAY command
295  if (rval)
296  {
297  QStringList pids;
298  m_rtsp->Play(pids);
299  m_oldpids = pids;
300  }
301  return rval;
302  }
303  return true;
304 }
305 
307 {
308  QUrl url;
309  url.setScheme("rtsp");
310  url.setPort(554);
311  url.setPath("/");
312 
313  // Discover the device using SSDP
314  QStringList devinfo = m_device.split(":");
315  if (devinfo.value(0).toUpper() == "UUID")
316  {
317  QString deviceId = QString("uuid:%1").arg(devinfo.value(1));
318  m_frontend = devinfo.value(3).toUInt();
319 
320  QString ip = SatIP::findDeviceIP(deviceId);
321  if (ip != nullptr)
322  {
323  LOG(VB_RECORD, LOG_INFO, LOC + QString("Discovered device %1 at %2").arg(deviceId).arg(ip));
324  }
325  else
326  {
327  LOG(VB_RECORD, LOG_ERR, LOC + QString("Failed to discover device %1, no IP found").arg(deviceId));
328  return false;
329  }
330 
331  url.setHost(ip);
332  }
333  else
334  {
335  // TODO: Handling of manual IP devices
336  }
337 
339  m_baseurl = url;
340 
341  return true;
342 }
343 
345 {
346  delete m_rtsp;
347  m_rtsp = nullptr;
348  m_baseurl = nullptr;
349 }
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:104
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:180
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:415
StreamHandler
Definition: streamhandler.h:57
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:211
MThread::setObjectName
void setObjectName(const QString &name)
Definition: mthread.cpp:241
SatIPStreamHandler::m_rtsp
SatIPRTSP * m_rtsp
Definition: satipstreamhandler.h:81
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:196
SatIP::tmode
static QString tmode(DTVTransmitMode tmode)
Definition: satiputils.cpp:308
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:128
satiputils.h
StreamHandler::m_pidInfo
PIDInfoMap m_pidInfo
Definition: streamhandler.h:138
mythlogging.h
StreamHandler::m_pidLock
QRecursiveMutex m_pidLock
Definition: streamhandler.h:135
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:306
SatIP::toTunerType
static int toTunerType(const QString &deviceid)
Definition: satiputils.cpp:177
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: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:244
DTVMultiplex::m_modSys
DTVModulationSystem m_modSys
Definition: dtvmultiplex.h:106
SatIP::gi
static QString gi(DTVGuardInterval gi)
Definition: satiputils.cpp:337
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:214
uint
unsigned int uint
Definition: compat.h:140
SatIP::pol
static QString pol(DTVPolarity pol)
Definition: satiputils.cpp:436
LOC
#define LOC
Definition: satipstreamhandler.cpp:23
mpegstreamdata.h
SatIPStreamHandler::Close
void Close(void)
Definition: satipstreamhandler.cpp:344
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:118
cardutil.h
StreamHandler::m_runningDesired
volatile bool m_runningDesired
Definition: streamhandler.h:120
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: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:72
SatIP::fec
static QString fec(DTVCodeRate fec)
Definition: satiputils.cpp:370
StreamHandler::m_bError
volatile bool m_bError
Definition: streamhandler.h:125
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:249
DTVTunerType::kTunerTypeDVBT2
static const int kTunerTypeDVBT2
Definition: dtvconfparserhelpers.h:97
SatIPStreamHandler::Tune
bool Tune(const DTVMultiplex &tuning)
Definition: satipstreamhandler.cpp:215
SatIPStreamHandler::s_handlers
static QMap< QString, SatIPStreamHandler * > s_handlers
Definition: satipstreamhandler.h:58
SatIP::mtype
static QString mtype(DTVModulation mtype)
Definition: satiputils.cpp:275
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