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