mixer/alsa: use cached values to work around rounding errors
This replaces 967af60327
with a more
effective workaround.
Closes https://github.com/MusicPlayerDaemon/MPD/issues/822
This commit is contained in:
parent
351b39e0c5
commit
04eb911a51
2
NEWS
2
NEWS
|
@ -13,6 +13,8 @@ ver 0.22.10 (not yet released)
|
||||||
* output
|
* output
|
||||||
- httpd: fix missing tag after seeking into a new song
|
- httpd: fix missing tag after seeking into a new song
|
||||||
- oss: fix channel order of multi-channel files
|
- oss: fix channel order of multi-channel files
|
||||||
|
* mixer
|
||||||
|
- alsa: fix yet more rounding errors
|
||||||
|
|
||||||
ver 0.22.9 (2021/06/23)
|
ver 0.22.9 (2021/06/23)
|
||||||
* database
|
* database
|
||||||
|
|
|
@ -80,6 +80,24 @@ class AlsaMixer final : public Mixer {
|
||||||
|
|
||||||
AlsaMixerMonitor *monitor;
|
AlsaMixerMonitor *monitor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These fields are our workaround for rounding errors when
|
||||||
|
* the resolution of a mixer knob isn't fine enough to
|
||||||
|
* represent all 101 possible values (0..100).
|
||||||
|
*
|
||||||
|
* "desired_volume" is the percent value passed to
|
||||||
|
* SetVolume(), and "resulting_volume" is the volume which was
|
||||||
|
* actually set, and would be returned by the next
|
||||||
|
* GetPercentVolume() call.
|
||||||
|
*
|
||||||
|
* When GetVolume() is called, we compare the
|
||||||
|
* "resulting_volume" with the value returned by
|
||||||
|
* GetPercentVolume(), and if it's the same, we're still on
|
||||||
|
* the same value that was previously set (but may have been
|
||||||
|
* rounded down or up).
|
||||||
|
*/
|
||||||
|
int desired_volume, resulting_volume;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AlsaMixer(EventLoop &_event_loop, MixerListener &_listener)
|
AlsaMixer(EventLoop &_event_loop, MixerListener &_listener)
|
||||||
:Mixer(alsa_mixer_plugin, _listener),
|
:Mixer(alsa_mixer_plugin, _listener),
|
||||||
|
@ -167,6 +185,17 @@ AlsaMixer::ElemCallback(snd_mixer_elem_t *elem, unsigned mask) noexcept
|
||||||
|
|
||||||
if (mask & SND_CTL_EVENT_MASK_VALUE) {
|
if (mask & SND_CTL_EVENT_MASK_VALUE) {
|
||||||
int volume = mixer.GetPercentVolume();
|
int volume = mixer.GetPercentVolume();
|
||||||
|
|
||||||
|
if (mixer.resulting_volume >= 0 &&
|
||||||
|
volume == mixer.resulting_volume)
|
||||||
|
/* still the same volume (this might be a
|
||||||
|
callback caused by SetVolume()) - switch to
|
||||||
|
desired_volume */
|
||||||
|
volume = mixer.desired_volume;
|
||||||
|
else
|
||||||
|
/* flush */
|
||||||
|
mixer.desired_volume = mixer.resulting_volume = -1;
|
||||||
|
|
||||||
mixer.listener.OnMixerVolumeChanged(mixer, volume);
|
mixer.listener.OnMixerVolumeChanged(mixer, volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,6 +282,8 @@ AlsaMixer::Setup()
|
||||||
void
|
void
|
||||||
AlsaMixer::Open()
|
AlsaMixer::Open()
|
||||||
{
|
{
|
||||||
|
desired_volume = resulting_volume = -1;
|
||||||
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = snd_mixer_open(&handle, 0);
|
err = snd_mixer_open(&handle, 0);
|
||||||
|
@ -291,7 +322,12 @@ AlsaMixer::GetVolume()
|
||||||
throw FormatRuntimeError("snd_mixer_handle_events() failed: %s",
|
throw FormatRuntimeError("snd_mixer_handle_events() failed: %s",
|
||||||
snd_strerror(err));
|
snd_strerror(err));
|
||||||
|
|
||||||
return GetPercentVolume();
|
int volume = GetPercentVolume();
|
||||||
|
if (resulting_volume >= 0 && volume == resulting_volume)
|
||||||
|
/* we're still on the value passed to SetVolume() */
|
||||||
|
volume = desired_volume;
|
||||||
|
|
||||||
|
return volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -299,12 +335,13 @@ AlsaMixer::SetVolume(unsigned volume)
|
||||||
{
|
{
|
||||||
assert(handle != nullptr);
|
assert(handle != nullptr);
|
||||||
|
|
||||||
double cur = GetNormalizedVolume();
|
int err = set_normalized_playback_volume(elem, 0.01*volume, 1);
|
||||||
int delta = volume - NormalizedToPercent(cur);
|
|
||||||
int err = set_normalized_playback_volume(elem, cur + 0.01*delta, delta);
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
throw FormatRuntimeError("failed to set ALSA volume: %s",
|
throw FormatRuntimeError("failed to set ALSA volume: %s",
|
||||||
snd_strerror(err));
|
snd_strerror(err));
|
||||||
|
|
||||||
|
desired_volume = volume;
|
||||||
|
resulting_volume = GetPercentVolume();
|
||||||
}
|
}
|
||||||
|
|
||||||
const MixerPlugin alsa_mixer_plugin = {
|
const MixerPlugin alsa_mixer_plugin = {
|
||||||
|
|
Loading…
Reference in New Issue