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;
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  int current_audio;
54 
55  struct v4l2_ext_control ext_ctrl;
56  struct v4l2_ext_controls ext_ctrls;
57 
58  memset(&ext_ctrl, 0, sizeof(struct v4l2_ext_control));
59  ext_ctrl.id = V4L2_CID_MPEG_AUDIO_ENCODING;
60 
61  ext_ctrls.reserved[0] = ext_ctrls.reserved[1] = 0;
62  ext_ctrls.count = 1;
63  ext_ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG;
64  ext_ctrls.controls = &ext_ctrl;
65 
66  if (ioctl(videofd, VIDIOC_G_EXT_CTRLS, &ext_ctrls) != 0)
67  {
68  LOG(VB_GENERAL, LOG_ERR, LOC +
69  "Unable to get current audio codecs for verification." + ENO);
70  return false;
71  }
72 
73  current_audio = ext_ctrls.controls->value;
74 
75  if (audtype != current_audio)
76  {
77  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Audio desired %1, current %2 "
78  "min %3 max %4")
79  .arg(audtype)
80  .arg(current_audio)
81  .arg(qctrl.minimum)
82  .arg(qctrl.maximum)
83  );
84 
85  ext_ctrl.id = V4L2_CID_MPEG_AUDIO_ENCODING;
86  ext_ctrl.value = audtype;
87  if (ioctl(videofd, VIDIOC_S_EXT_CTRLS, &ext_ctrls) == 0)
88  {
89  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Changed audio encoding "
90  "from %1 to %2.")
91  .arg(current_audio)
92  .arg(audtype)
93  );
94  }
95  else
96  {
97  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to changed audio "
98  "encoding from %1 to %2.")
99  .arg(current_audio)
100  .arg(audtype)
101  + ENO
102  );
103  }
104 
105  return false;
106  }
107 
108  return true;
109 }
110 
111 /* m_stable_time is used to designate how long we need to see a stable
112  * resolution reported from the HD-PVR driver, before we consider it a
113  * good lock. In my testing 2 seconds is safe, while 1 second worked
114  * most of the time. --jp
115  */
117 {
118  struct v4l2_format vfmt;
119  memset(&vfmt, 0, sizeof(vfmt));
120  vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
121 
122  if ((ioctl(videofd, VIDIOC_G_FMT, &vfmt) == 0) &&
123  vfmt.fmt.pix.width && m_width == vfmt.fmt.pix.width &&
124  VerifyHDPVRaudio(videofd))
125  {
126  if (!m_timer.isRunning())
127  {
128  LOG(VB_RECORD, LOG_ERR, QString("hd-pvr resolution %1 x %2")
129  .arg(vfmt.fmt.pix.width).arg(vfmt.fmt.pix.height));
130  ++m_lock_cnt;
131  m_timer.start();
132  }
133  else if (m_timer.elapsed() > m_stable_time)
134  {
135  LOG(VB_RECORD, LOG_ERR, QString("hd-pvr stable at %1 x %2")
136  .arg(vfmt.fmt.pix.width).arg(vfmt.fmt.pix.height));
137  m_timer.stop();
138  return true;
139  }
140  else
141  {
142  QMutexLocker locker(&m_statusLock);
144  }
145  }
146  else
147  {
148  if (--m_log_idx == 0)
149  {
150  LOG(VB_RECORD, LOG_ERR, "hd-pvr waiting for valid resolution");
151  m_log_idx = 40;
152  }
153  m_width = vfmt.fmt.pix.width;
154  m_timer.stop();
155  QMutexLocker locker(&m_statusLock);
157  }
158 
159  return false;
160 }
161 
163 {
165 
166  {
167  QMutexLocker locker(&m_statusLock);
168  if (!m_scriptStatus.IsGood())
169  return;
170  }
171 
172  if (!m_running || m_exit)
173  return;
174 
175  int videofd = m_channel->GetFd();
176  if (videofd < 0)
177  return;
178 
179  bool isLocked = false;
180  if (m_usingv4l2)
181  {
182  if (m_driver == "hdpvr")
183  isLocked = handleHDPVR(videofd);
184  else
185  {
186  struct v4l2_tuner tuner;
187  memset(&tuner, 0, sizeof(tuner));
188 
189  if (ioctl(videofd, VIDIOC_G_TUNER, &tuner, 0) < 0)
190  {
191  LOG(VB_GENERAL, LOG_ERR, "Failed to probe signal (v4l2)" + ENO);
192  }
193  else
194  {
195  isLocked = (tuner.signal != 0);
196  }
197  }
198  }
199 #ifdef USING_V4L1
200  else
201  {
202  struct video_tuner tuner;
203  memset(&tuner, 0, sizeof(tuner));
204 
205  if (ioctl(videofd, VIDIOCGTUNER, &tuner, 0) < 0)
206  {
207  LOG(VB_GENERAL, LOG_ERR, "Failed to probe signal (v4l1)" + ENO);
208  }
209  else
210  {
211  isLocked = tuner.signal;
212  }
213  }
214 #endif // USING_V4L1
215 
216  {
217  QMutexLocker locker(&m_statusLock);
218  m_signalLock.SetValue(isLocked);
219  if (isLocked)
221  }
222 
223  EmitStatus();
224  if (IsAllGood())
226 }
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:2117
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: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 m_signalStrength
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:79