MythTV  master
analogsignalmonitor.cpp
Go to the documentation of this file.
1 // -*- Mode: c++ -*-
2 // Copyright (c) 2005, Daniel Thor Kristjansson
3 
4 #include <cerrno>
5 #include <unistd.h>
6 #include <sys/ioctl.h>
7 #include <poll.h>
8 
9 #ifdef USING_V4L1
10 #include <linux/videodev.h>
11 #endif // USING_V4L1
12 
13 #include "mythlogging.h"
14 #include "analogsignalmonitor.h"
15 #include "v4lchannel.h"
16 
17 #define LOC QString("AnalogSigMon[%1](%2): ") \
18  .arg(m_inputid).arg(m_channel->GetDevice())
19 
21  V4LChannel *_channel,
22  bool _release_stream,
23  uint64_t _flags)
24  : SignalMonitor(db_cardnum, _channel, _release_stream, _flags)
25 {
26  int videofd = m_channel->GetFd();
27  if (videofd >= 0)
28  {
29  uint32_t caps = 0;
30  if (!CardUtil::GetV4LInfo(videofd, m_card, m_driver, m_version, caps))
31  return;
32 
33  m_usingV4l2 = ((caps & V4L2_CAP_VIDEO_CAPTURE) != 0U);
34  LOG(VB_RECORD, LOG_INFO, QString("card '%1' driver '%2' version '%3'")
35  .arg(m_card).arg(m_driver).arg(m_version));
36  }
37 }
38 
40 {
41  struct v4l2_queryctrl qctrl {};
42  qctrl.id = V4L2_CID_MPEG_AUDIO_ENCODING;
43 
44  int audtype = V4L2_MPEG_AUDIO_ENCODING_AC3;
45 
46  if (ioctl(videofd, VIDIOC_QUERYCTRL, &qctrl) != 0)
47  {
48  LOG(VB_GENERAL, LOG_ERR, LOC +
49  "Unable to get supported audio codecs for verification." + ENO);
50  return false;
51  }
52 
53  struct v4l2_ext_control ext_ctrl {};
54  struct v4l2_ext_controls ext_ctrls {};
55 
56  ext_ctrl.id = V4L2_CID_MPEG_AUDIO_ENCODING;
57 
58  ext_ctrls.reserved[0] = ext_ctrls.reserved[1] = 0;
59  ext_ctrls.count = 1;
60  ext_ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG;
61  ext_ctrls.controls = &ext_ctrl;
62 
63  if (ioctl(videofd, VIDIOC_G_EXT_CTRLS, &ext_ctrls) != 0)
64  {
65  LOG(VB_GENERAL, LOG_ERR, LOC +
66  "Unable to get current audio codecs for verification." + ENO);
67  return false;
68  }
69 
70  int current_audio = ext_ctrls.controls->value;
71 
72  if (audtype != current_audio)
73  {
74  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Audio desired %1, current %2 "
75  "min %3 max %4")
76  .arg(audtype)
77  .arg(current_audio)
78  .arg(qctrl.minimum)
79  .arg(qctrl.maximum)
80  );
81 
82  ext_ctrl.id = V4L2_CID_MPEG_AUDIO_ENCODING;
83  ext_ctrl.value = audtype;
84  if (ioctl(videofd, VIDIOC_S_EXT_CTRLS, &ext_ctrls) == 0)
85  {
86  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Changed audio encoding "
87  "from %1 to %2.")
88  .arg(current_audio)
89  .arg(audtype)
90  );
91  }
92  else
93  {
94  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to changed audio "
95  "encoding from %1 to %2.")
96  .arg(current_audio)
97  .arg(audtype)
98  + ENO
99  );
100  }
101 
102  return false;
103  }
104 
105  return true;
106 }
107 
108 /* m_stableTime is used to designate how long we need to see a stable
109  * resolution reported from the HD-PVR driver, before we consider it a
110  * good lock. In my testing 2 seconds is safe, while 1 second worked
111  * most of the time. --jp
112  */
114 {
115  struct v4l2_format vfmt {};
116  vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
117 
118  if ((ioctl(videofd, VIDIOC_G_FMT, &vfmt) == 0) &&
119  vfmt.fmt.pix.width && m_width == vfmt.fmt.pix.width &&
120  VerifyHDPVRaudio(videofd))
121  {
122  if (!m_timer.isRunning())
123  {
124  LOG(VB_RECORD, LOG_ERR, QString("hd-pvr resolution %1 x %2")
125  .arg(vfmt.fmt.pix.width).arg(vfmt.fmt.pix.height));
126  ++m_lockCnt;
127  m_timer.start();
128  }
129  else if (m_timer.elapsed() > m_stableTime)
130  {
131  LOG(VB_RECORD, LOG_ERR, QString("hd-pvr stable at %1 x %2")
132  .arg(vfmt.fmt.pix.width).arg(vfmt.fmt.pix.height));
133  m_timer.stop();
134  return true;
135  }
136  else
137  {
138  QMutexLocker locker(&m_statusLock);
140  }
141  }
142  else
143  {
144  if (--m_logIdx == 0)
145  {
146  LOG(VB_RECORD, LOG_ERR, "hd-pvr waiting for valid resolution");
147  m_logIdx = 40;
148  }
149  m_width = vfmt.fmt.pix.width;
150  m_timer.stop();
151  QMutexLocker locker(&m_statusLock);
153  }
154 
155  return false;
156 }
157 
159 {
161 
162  {
163  QMutexLocker locker(&m_statusLock);
164  if (!m_scriptStatus.IsGood())
165  return;
166  }
167 
168  if (!m_running || m_exit)
169  return;
170 
171  int videofd = m_channel->GetFd();
172  if (videofd < 0)
173  return;
174 
175  bool isLocked = false;
176  if (m_usingV4l2)
177  {
178  if (m_driver == "hdpvr")
179  isLocked = handleHDPVR(videofd);
180  else
181  {
182  struct v4l2_tuner tuner {};
183 
184  if (ioctl(videofd, VIDIOC_G_TUNER, &tuner, 0) < 0)
185  {
186  LOG(VB_GENERAL, LOG_ERR, "Failed to probe signal (v4l2)" + ENO);
187  }
188  else
189  {
190  isLocked = (tuner.signal != 0);
191  }
192  }
193  }
194 #ifdef USING_V4L1
195  else
196  {
197  struct video_tuner tuner;
198  memset(&tuner, 0, sizeof(tuner));
199 
200  if (ioctl(videofd, VIDIOCGTUNER, &tuner, 0) < 0)
201  {
202  LOG(VB_GENERAL, LOG_ERR, "Failed to probe signal (v4l1)" + ENO);
203  }
204  else
205  {
206  isLocked = tuner.signal;
207  }
208  }
209 #endif // USING_V4L1
210 
211  {
212  QMutexLocker locker(&m_statusLock);
213  m_signalLock.SetValue(isLocked);
214  if (isLocked)
216  }
217 
218  EmitStatus();
219  if (IsAllGood())
221 }
SignalMonitorValue m_scriptStatus
void UpdateValues(void) override
This should be overridden to actually do signal monitoring.
QMutex m_statusLock
#define LOC
bool isRunning(void) const
Returns true if start() or restart() has been called at least once since construction and since any c...
Definition: mythtimer.cpp:134
static bool GetV4LInfo(int videofd, QString &input, QString &driver, uint32_t &version, uint32_t &capabilities)
Definition: cardutil.cpp:2157
void SetValue(int _value)
bool handleHDPVR(int videofd)
bool VerifyHDPVRaudio(int videofd)
ChannelBase * m_channel
volatile bool m_exit
void SendMessageAllGood(void)
volatile bool m_running
AnalogSignalMonitor(int db_cardnum, V4LChannel *_channel, bool _release_stream, uint64_t _flags=kSigMon_WaitForSig)
Implements tuning for TV cards using the V4L driver API, both versions 1 and 2.
Definition: v4lchannel.h:35
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:109
Signal monitoring base class.
Definition: signalmonitor.h:32
SignalMonitorValue m_signalStrength
int elapsed(void)
Returns milliseconds elapsed since last start() or restart()
Definition: mythtimer.cpp:90
virtual int GetFd(void) const
Returns file descriptor, -1 if it does not exist.
Definition: channelbase.h:57
bool IsGood() const
Returns true if the value is equal to the threshold, or on the right side of the threshold (depends o...
void stop(void)
Stops timer, next call to isRunning() will return false and any calls to elapsed() or restart() will ...
Definition: mythtimer.cpp:77
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47
SignalMonitorValue m_signalLock
virtual void EmitStatus(void)
virtual void UpdateValues(void)
This should be overridden to actually do signal monitoring.
virtual bool IsAllGood(void) const
Definition: signalmonitor.h:83
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:41