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 "libmythbase/mthread.h"
12 
13 #include "volumebase.h"
14 
15 
16 namespace {
18 {
19  VolumeWriteBackThread() : MThread("VolumeWriteBack") { }
20 
21  public:
22  // Singleton
24  {
25  QMutexLocker lock(&s_mutex);
26  static auto *s_instance = new VolumeWriteBackThread;
27  return s_instance;
28  }
29 
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  [[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  static constexpr std::chrono::milliseconds holdoff { 500ms }; // 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  usleep(holdoff); // cppcheck-suppress usleepCalled
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 : std::uint8_t { kStopped, kRunning, kFinished } m_state {kStopped};
92  int m_volume {-1};
93 };
94 
95 QMutex VolumeWriteBackThread::s_mutex;
96 } // namespace
97 
98 
100 {
101  m_internalVol = gCoreContext->GetBoolSetting("MythControlsVolume", true);
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_swvolSetting)
114  return;
115  m_swvol = set;
116 }
117 
119 {
120  return m_volume;
121 }
122 
124 {
125  m_volume = std::clamp(value, 0, 100);
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_currentMuteState = mstate;
140  UpdateVolume();
141  return m_currentMuteState;
142 }
143 
145 {
146  bool is_muted = GetMuteState() == kMuteAll;
147  SetMuteState((is_muted) ? kMuteOff : kMuteAll);
148 }
149 
151 {
152  return m_currentMuteState;
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;
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_currentMuteState == kMuteLeft)
200  // {
201  // SetVolumeChannel(0, 0);
202  // }
203  // else if (m_currentMuteState == 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
216 }
217 
218 void VolumeBase::SetChannels(int new_channels)
219 {
220  m_channels = new_channels;
221 }
VolumeBase::SetCurrentVolume
virtual void SetCurrentVolume(int value)
Definition: volumebase.cpp:123
VolumeBase::GetVolumeChannel
virtual int GetVolumeChannel(int channel) const =0
anonymous_namespace{volumebase.cpp}::VolumeWriteBackThread::Instance
static VolumeWriteBackThread * Instance()
Definition: volumebase.cpp:23
anonymous_namespace{volumebase.cpp}::VolumeWriteBackThread::m_mutex
QMutex m_mutex
Definition: volumebase.cpp:90
anonymous_namespace{volumebase.cpp}::VolumeWriteBackThread
Definition: volumebase.cpp:17
VolumeBase::AdjustCurrentVolume
virtual void AdjustCurrentVolume(int change)
Definition: volumebase.cpp:132
VolumeBase::GetCurrentVolume
virtual uint GetCurrentVolume(void) const
Definition: volumebase.cpp:118
anonymous_namespace{volumebase.cpp}::VolumeWriteBackThread::run
void run(void) override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: volumebase.cpp:56
VolumeBase::GetSWVolume
virtual int GetSWVolume(void)=0
VolumeBase::m_internalVol
bool m_internalVol
Definition: volumebase.h:43
VolumeBase::SetMuteState
virtual MuteState SetMuteState(MuteState)
Definition: volumebase.cpp:137
VolumeBase::SyncVolume
void SyncVolume(void)
Definition: volumebase.cpp:209
anonymous_namespace{volumebase.cpp}::VolumeWriteBackThread::SetVolume
void SetVolume(int value)
Definition: volumebase.cpp:33
VolumeBase::m_swvolSetting
bool m_swvolSetting
Definition: volumebase.h:50
VolumeBase::ToggleMute
virtual void ToggleMute(void)
Definition: volumebase.cpp:144
anonymous_namespace{volumebase.cpp}::VolumeWriteBackThread::VolumeWriteBackThread
VolumeWriteBackThread()
Definition: volumebase.cpp:19
VolumeBase::m_volume
int m_volume
Definition: volumebase.h:47
VolumeBase::SetSWVolume
virtual void SetSWVolume(int new_volume, bool save)=0
VolumeBase::GetMuteState
virtual MuteState GetMuteState(void) const
Definition: volumebase.cpp:150
VolumeBase::NextMuteState
static MuteState NextMuteState(MuteState)
Definition: volumebase.cpp:155
VolumeBase::VolumeBase
VolumeBase()
Definition: volumebase.cpp:99
uint
unsigned int uint
Definition: compat.h:81
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
VolumeBase::SWVolume
bool SWVolume(void) const
Definition: volumebase.cpp:106
clamp
static eu8 clamp(eu8 value, eu8 low, eu8 high)
Definition: pxsup2dast.c:204
MuteState
MuteState
Definition: volumebase.h:8
volumebase.h
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:910
anonymous_namespace{volumebase.cpp}::VolumeWriteBackThread::s_mutex
static QMutex s_mutex
Definition: volumebase.cpp:89
anonymous_namespace{volumebase.cpp}::VolumeWriteBackThread::kStopped
@ kStopped
Definition: volumebase.cpp:91
VolumeBase::m_channels
int m_channels
Definition: volumebase.h:51
mythcorecontext.h
VolumeBase::m_swvol
bool m_swvol
Definition: volumebase.h:49
MThread
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:48
kMuteLeft
@ kMuteLeft
Definition: volumebase.h:10
mthread.h
VolumeBase::SetVolumeChannel
virtual void SetVolumeChannel(int channel, int volume)=0
VolumeBase::SetChannels
void SetChannels(int new_channels)
Definition: volumebase.cpp:218
VolumeBase::UpdateVolume
void UpdateVolume(void)
Definition: volumebase.cpp:178
kMuteRight
@ kMuteRight
Definition: volumebase.h:11
MythCoreContext::IsExiting
bool IsExiting(void)
Definition: mythcorecontext.cpp:2125
kMuteOff
@ kMuteOff
Definition: volumebase.h:9
MythCoreContext::SaveSetting
void SaveSetting(const QString &key, int newValue)
Definition: mythcorecontext.cpp:885
kMuteAll
@ kMuteAll
Definition: volumebase.h:12
VolumeBase::m_currentMuteState
MuteState m_currentMuteState
Definition: volumebase.h:48
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:902