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(inputid).arg(channel->GetDevice())
19 
21  V4LChannel *_channel,
22  bool _release_stream,
23  uint64_t _flags)
24  : SignalMonitor(db_cardnum, _channel, _release_stream, _flags),
25  m_usingv4l2(false), m_version(0), m_width(0), m_stable_time(2000),
26  m_lock_cnt(0), m_log_idx(40)
27 {
28  int videofd = channel->GetFd();
29  if (videofd >= 0)
30  {
31  uint32_t caps;
32  if (!CardUtil::GetV4LInfo(videofd, m_card, m_driver, m_version, caps))
33  return;
34 
35  m_usingv4l2 = !!(caps & V4L2_CAP_VIDEO_CAPTURE);
36  LOG(VB_RECORD, LOG_INFO, QString("card '%1' driver '%2' version '%3'")
37  .arg(m_card).arg(m_driver).arg(m_version));
38  }
39 }
40 
42 {
43  struct v4l2_queryctrl qctrl;
44  qctrl.id = V4L2_CID_MPEG_AUDIO_ENCODING;
45 
46  int audtype = V4L2_MPEG_AUDIO_ENCODING_AC3;
47 
48  if (ioctl(videofd, VIDIOC_QUERYCTRL, &qctrl) != 0)
49  {
50  LOG(VB_GENERAL, LOG_ERR, LOC +
51  "Unable to get supported audio codecs for verification." + ENO);
52  return false;
53  }
54 
55  int current_audio;
56 
57  struct v4l2_ext_control ext_ctrl;
58  struct v4l2_ext_controls ext_ctrls;
59 
60  memset(&ext_ctrl, 0, sizeof(struct v4l2_ext_control));
61  ext_ctrl.id = V4L2_CID_MPEG_AUDIO_ENCODING;
62 
63  ext_ctrls.reserved[0] = ext_ctrls.reserved[1] = 0;
64  ext_ctrls.count = 1;
65  ext_ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG;
66  ext_ctrls.controls = &ext_ctrl;
67 
68  if (ioctl(videofd, VIDIOC_G_EXT_CTRLS, &ext_ctrls) != 0)
69  {
70  LOG(VB_GENERAL, LOG_ERR, LOC +
71  "Unable to get current audio codecs for verification." + ENO);
72  return false;
73  }
74 
75  current_audio = ext_ctrls.controls->value;
76 
77  if (audtype != current_audio)
78  {
79  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Audio desired %1, current %2 "
80  "min %3 max %4")
81  .arg(audtype)
82  .arg(current_audio)
83  .arg(qctrl.minimum)
84  .arg(qctrl.maximum)
85  );
86 
87  ext_ctrl.id = V4L2_CID_MPEG_AUDIO_ENCODING;
88  ext_ctrl.value = audtype;
89  if (ioctl(videofd, VIDIOC_S_EXT_CTRLS, &ext_ctrls) == 0)
90  {
91  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Changed audio encoding "
92  "from %1 to %2.")
93  .arg(current_audio)
94  .arg(audtype)
95  );
96  }
97  else
98  {
99  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to changed audio "
100  "encoding from %1 to %2.")
101  .arg(current_audio)
102  .arg(audtype)
103  + ENO
104  );
105  }
106 
107  return false;
108  }
109 
110  return true;
111 }
112 
113 /* m_stable_time is used to designate how long we need to see a stable
114  * resolution reported from the HD-PVR driver, before we consider it a
115  * good lock. In my testing 2 seconds is safe, while 1 second worked
116  * most of the time. --jp
117  */
119 {
120  struct v4l2_format vfmt;
121  memset(&vfmt, 0, sizeof(vfmt));
122  vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
123 
124  if ((ioctl(videofd, VIDIOC_G_FMT, &vfmt) == 0) &&
125  vfmt.fmt.pix.width && m_width == vfmt.fmt.pix.width &&
126  VerifyHDPVRaudio(videofd))
127  {
128  if (!m_timer.isRunning())
129  {
130  LOG(VB_RECORD, LOG_ERR, QString("hd-pvr resolution %1 x %2")
131  .arg(vfmt.fmt.pix.width).arg(vfmt.fmt.pix.height));
132  ++m_lock_cnt;
133  m_timer.start();
134  }
135  else if (m_timer.elapsed() > m_stable_time)
136  {
137  LOG(VB_RECORD, LOG_ERR, QString("hd-pvr stable at %1 x %2")
138  .arg(vfmt.fmt.pix.width).arg(vfmt.fmt.pix.height));
139  m_timer.stop();
140  return true;
141  }
142  else
143  {
144  QMutexLocker locker(&statusLock);
146  }
147  }
148  else
149  {
150  if (--m_log_idx == 0)
151  {
152  LOG(VB_RECORD, LOG_ERR, "hd-pvr waiting for valid resolution");
153  m_log_idx = 40;
154  }
155  m_width = vfmt.fmt.pix.width;
156  m_timer.stop();
157  QMutexLocker locker(&statusLock);
159  }
160 
161  return false;
162 }
163 
165 {
167 
168  {
169  QMutexLocker locker(&statusLock);
170  if (!scriptStatus.IsGood())
171  return;
172  }
173 
174  if (!running || exit)
175  return;
176 
177  int videofd = channel->GetFd();
178  if (videofd < 0)
179  return;
180 
181  bool isLocked = false;
182  if (m_usingv4l2)
183  {
184  if (m_driver == "hdpvr")
185  isLocked = handleHDPVR(videofd);
186  else
187  {
188  struct v4l2_tuner tuner;
189  memset(&tuner, 0, sizeof(tuner));
190 
191  if (ioctl(videofd, VIDIOC_G_TUNER, &tuner, 0) < 0)
192  {
193  LOG(VB_GENERAL, LOG_ERR, "Failed to probe signal (v4l2)" + ENO);
194  }
195  else
196  {
197  isLocked = tuner.signal;
198  }
199  }
200  }
201 #ifdef USING_V4L1
202  else
203  {
204  struct video_tuner tuner;
205  memset(&tuner, 0, sizeof(tuner));
206 
207  if (ioctl(videofd, VIDIOCGTUNER, &tuner, 0) < 0)
208  {
209  LOG(VB_GENERAL, LOG_ERR, "Failed to probe signal (v4l1)" + ENO);
210  }
211  else
212  {
213  isLocked = tuner.signal;
214  }
215  }
216 #endif // USING_V4L1
217 
218  {
219  QMutexLocker locker(&statusLock);
220  signalLock.SetValue(isLocked);
221  if (isLocked)
223  }
224 
225  EmitStatus();
226  if (IsAllGood())
228 }
void UpdateValues(void) override
This should be overridden to actually do signal monitoring.
#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
SignalMonitorValue signalLock
static bool GetV4LInfo(int videofd, QString &input, QString &driver, uint32_t &version, uint32_t &capabilities)
Definition: cardutil.cpp:1667
void SetValue(int _value)
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
bool handleHDPVR(int videofd)
bool VerifyHDPVRaudio(int videofd)
void SendMessageAllGood(void)
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:32
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:99
int elapsed(void) const
Returns milliseconds elapsed since last start() or restart()
Definition: mythtimer.cpp:90
Signal monitoring base class.
Definition: signalmonitor.h:32
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
SignalMonitorValue signalStrength
SignalMonitorValue scriptStatus
ChannelBase * channel
virtual int GetFd(void) const
Returns file descriptor, -1 if it does not exist.
Definition: channelbase.h:57
volatile bool running
bool IsGood() const
Returns true if the value is equal to the threshold, or on the right side of the threshold (depends o...
volatile bool exit
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
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:79