MythTV  master
volumebase.cpp
Go to the documentation of this file.
1 #include <cstdio>
2 #include <cstdlib>
3 
4 #include <algorithm>
5 using namespace std;
6 
7 #include <QString>
8 #include <QMutex>
9 #include <QMutexLocker>
10 
11 #include "volumebase.h"
12 #include "mythcorecontext.h"
13 #include "mthread.h"
14 
15 
16 namespace {
17 class VolumeWriteBackThread : public MThread
18 {
19  VolumeWriteBackThread() : MThread("VolumeWriteBack") { }
20 
21  public:
22  // Singleton
23  static VolumeWriteBackThread *Instance()
24  {
25  QMutexLocker lock(&s_mutex);
26  static VolumeWriteBackThread *s_instance = new VolumeWriteBackThread;
27  return s_instance;
28  }
29 
30  VolumeWriteBackThread(const VolumeWriteBackThread &) = delete;
31  VolumeWriteBackThread & operator =(const VolumeWriteBackThread &) = delete;
32 
33  void SetVolume(int value)
34  {
35  QMutexLocker lock(&m_mutex);
36 
37  if (m_volume == value)
38  return;
39  m_volume = value;
40 
41  switch (m_state)
42  {
43  case kRunning:
44  break;
45  case kFinished:
46  wait();
47  [[clang::fallthrough]];
48  case kStopped:
49  m_state = kRunning;
50  start();
51  break;
52  }
53  }
54 
55  protected:
56  void run(void) override // MThread
57  {
58  m_state = kRunning;
59  RunProlog();
60 
61  const int holdoff = 500; // min ms between Db writes
62  QString controlLabel = gCoreContext->GetSetting("MixerControl", "PCM");
63  controlLabel += "MixerVolume";
64 
65  QMutexLocker lock(&m_mutex);
66  while (gCoreContext && !gCoreContext->IsExiting())
67  {
68  int volume = m_volume;
69  lock.unlock();
70 
71  // Update the dbase with the new volume
72  gCoreContext->SaveSetting(controlLabel, volume);
73 
74  // Ignore further volume changes for the holdoff period
75  setTerminationEnabled(true);
76  msleep(holdoff);
77  setTerminationEnabled(false);
78 
79  lock.relock();
80  if (volume == m_volume)
81  break;
82  }
83 
84  m_state = kFinished;
85  RunEpilog();
86  }
87 
88  private:
89  static QMutex s_mutex;
90  QMutex mutable m_mutex;
91  enum { kStopped, kRunning, kFinished } m_state {kStopped};
92  int m_volume {-1};
93 };
94 
95 QMutex VolumeWriteBackThread::s_mutex;
96 } // namespace
97 
98 
100 {
101  internal_vol = gCoreContext->GetBoolSetting("MythControlsVolume", true);
102  m_swvol = m_swvol_setting =
103  (gCoreContext->GetSetting("MixerDevice", "default").toLower() == "software");
104 }
105 
106 bool VolumeBase::SWVolume(void) const
107 {
108  return m_swvol;
109 }
110 
111 void VolumeBase::SWVolume(bool set)
112 {
113  if (m_swvol_setting)
114  return;
115  m_swvol = set;
116 }
117 
119 {
120  return m_volume;
121 }
122 
124 {
125  m_volume = max(min(value, 100), 0);
126  UpdateVolume();
127 
128  // Throttle Db writes
129  VolumeWriteBackThread::Instance()->SetVolume(m_volume);
130 }
131 
133 {
134  SetCurrentVolume(m_volume + change);
135 }
136 
138 {
139  m_current_mute_state = mstate;
140  UpdateVolume();
141  return m_current_mute_state;
142 }
143 
145 {
146  bool is_muted = GetMuteState() == kMuteAll;
147  SetMuteState((is_muted) ? kMuteOff : kMuteAll);
148 }
149 
151 {
152  return m_current_mute_state;
153 }
154 
156 {
157  MuteState next = cur;
158 
159  switch (cur)
160  {
161  case kMuteOff:
162  next = kMuteLeft;
163  break;
164  case kMuteLeft:
165  next = kMuteRight;
166  break;
167  case kMuteRight:
168  next = kMuteAll;
169  break;
170  case kMuteAll:
171  next = kMuteOff;
172  break;
173  }
174 
175  return (next);
176 }
177 
179 {
180  int new_volume = m_volume;
181  if (m_current_mute_state == kMuteAll)
182  {
183  new_volume = 0;
184  }
185 
186  if (m_swvol)
187  {
188  SetSWVolume(new_volume, false);
189  return;
190  }
191 
192  for (int i = 0; i < m_channels; i++)
193  {
194  SetVolumeChannel(i, new_volume);
195  }
196 
197  // Individual channel muting is handled in GetAudioData,
198  // this code demonstrates the old method.
199  // if (m_current_mute_state == kMuteLeft)
200  // {
201  // SetVolumeChannel(0, 0);
202  // }
203  // else if (m_current_mute_state == kMuteRight)
204  // {
205  // SetVolumeChannel(1, 0);
206  // }
207 }
208 
210 {
211  // Read the volume from the audio driver and setup our internal state to match
212  if (m_swvol)
213  m_volume = GetSWVolume();
214  else
215  m_volume = GetVolumeChannel(0);
216 }
217 
218 void VolumeBase::SetChannels(int new_channels)
219 {
220  m_channels = new_channels;
221 }
virtual uint GetCurrentVolume(void) const
Definition: volumebase.cpp:118
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:46
virtual void SetCurrentVolume(int value)
Definition: volumebase.cpp:123
void SaveSetting(const QString &key, int newValue)
virtual void ToggleMute(void)
Definition: volumebase.cpp:144
MuteState
Definition: volumebase.h:6
unsigned int uint
Definition: compat.h:140
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static MuteState NextMuteState(MuteState)
Definition: volumebase.cpp:155
bool SWVolume(void) const
Definition: volumebase.cpp:106
virtual MuteState SetMuteState(MuteState)
Definition: volumebase.cpp:137
virtual void AdjustCurrentVolume(int change)
Definition: volumebase.cpp:132
void UpdateVolume(void)
Definition: volumebase.cpp:178
static int run(MythMediaDevice *dev=nullptr, bool startRandomShow=false)
void SyncVolume(void)
Definition: volumebase.cpp:209
QString GetSetting(const QString &key, const QString &defaultval="")
PictureAttribute next(PictureAttributeSupported supported, PictureAttribute attribute)
bool GetBoolSetting(const QString &key, bool defaultval=false)
void SetChannels(int new_channels)
Definition: volumebase.cpp:218
virtual MuteState GetMuteState(void) const
Definition: volumebase.cpp:150