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