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