
Move audio output state check ahead of mixer check and force volume applying even for disabled software mixed outputs. This fixes incorrect software mixer volume that used to occur when volume was changed while output being disabled. This is easily reproduced with following sequence of commands on multi-output software mixed MPD setup. mpc volume 38; mpc disable 3; mpc volume 88; mpc enable 3 On current MPD, following commands would result in output 3 playing at volume 38, while all other enabled outputs would play at volume 88. Moreover, global volume would display average of outputs real volumes. In my case, it's 75. After applying this patch, following commands would produce expected behavior. All outputs play at expected (88) volume. And volume is correctly displayed as 88. Closes https://github.com/MusicPlayerDaemon/MPD/issues/1423 Signed-off-by: Vitaly Ostrosablin tmp6154@yandex.ru Signed-off-by: Vitaly Ostrosablin <tmp6154@yandex.ru>
161 lines
3.5 KiB
C++
161 lines
3.5 KiB
C++
/*
|
|
* Copyright 2003-2021 The Music Player Daemon Project
|
|
* http://www.musicpd.org
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include "output/MultipleOutputs.hxx"
|
|
#include "MixerControl.hxx"
|
|
#include "MixerInternal.hxx"
|
|
#include "MixerList.hxx"
|
|
#include "lib/fmt/ExceptionFormatter.hxx"
|
|
#include "pcm/Volume.hxx"
|
|
#include "util/Domain.hxx"
|
|
#include "Log.hxx"
|
|
|
|
#include <cassert>
|
|
|
|
static constexpr Domain mixer_domain("mixer");
|
|
|
|
gcc_pure
|
|
static int
|
|
output_mixer_get_volume(const AudioOutputControl &ao) noexcept
|
|
{
|
|
auto *mixer = ao.GetMixer();
|
|
if (mixer == nullptr)
|
|
return -1;
|
|
|
|
/* software mixers are always considered, even if they are
|
|
disabled */
|
|
if (!ao.IsEnabled() && !mixer->IsPlugin(software_mixer_plugin))
|
|
return -1;
|
|
|
|
try {
|
|
return mixer_get_volume(mixer);
|
|
} catch (...) {
|
|
FmtError(mixer_domain,
|
|
"Failed to read mixer for '{}': {}",
|
|
ao.GetName(), std::current_exception());
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int
|
|
MultipleOutputs::GetVolume() const noexcept
|
|
{
|
|
unsigned ok = 0;
|
|
int total = 0;
|
|
|
|
for (const auto &ao : outputs) {
|
|
int volume = output_mixer_get_volume(*ao);
|
|
if (volume >= 0) {
|
|
total += volume;
|
|
++ok;
|
|
}
|
|
}
|
|
|
|
if (ok == 0)
|
|
return -1;
|
|
|
|
return total / ok;
|
|
}
|
|
|
|
static bool
|
|
output_mixer_set_volume(AudioOutputControl &ao, unsigned volume) noexcept
|
|
{
|
|
assert(volume <= 100);
|
|
|
|
auto *mixer = ao.GetMixer();
|
|
if (mixer == nullptr)
|
|
return false;
|
|
|
|
/* software mixers are always updated, even if they are
|
|
disabled */
|
|
if (!ao.IsEnabled() && !mixer->IsPlugin(software_mixer_plugin))
|
|
return false;
|
|
|
|
try {
|
|
mixer_set_volume(mixer, volume);
|
|
return true;
|
|
} catch (...) {
|
|
FmtError(mixer_domain,
|
|
"Failed to set mixer for '{}': {}",
|
|
ao.GetName(), std::current_exception());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool
|
|
MultipleOutputs::SetVolume(unsigned volume) noexcept
|
|
{
|
|
assert(volume <= 100);
|
|
|
|
bool success = false;
|
|
for (const auto &ao : outputs)
|
|
success = output_mixer_set_volume(*ao, volume)
|
|
|| success;
|
|
|
|
return success;
|
|
}
|
|
|
|
static int
|
|
output_mixer_get_software_volume(const AudioOutputControl &ao) noexcept
|
|
{
|
|
if (!ao.IsEnabled())
|
|
return -1;
|
|
|
|
auto *mixer = ao.GetMixer();
|
|
if (mixer == nullptr || !mixer->IsPlugin(software_mixer_plugin))
|
|
return -1;
|
|
|
|
return mixer_get_volume(mixer);
|
|
}
|
|
|
|
int
|
|
MultipleOutputs::GetSoftwareVolume() const noexcept
|
|
{
|
|
unsigned ok = 0;
|
|
int total = 0;
|
|
|
|
for (const auto &ao : outputs) {
|
|
int volume = output_mixer_get_software_volume(*ao);
|
|
if (volume >= 0) {
|
|
total += volume;
|
|
++ok;
|
|
}
|
|
}
|
|
|
|
if (ok == 0)
|
|
return -1;
|
|
|
|
return total / ok;
|
|
}
|
|
|
|
void
|
|
MultipleOutputs::SetSoftwareVolume(unsigned volume) noexcept
|
|
{
|
|
assert(volume <= PCM_VOLUME_1);
|
|
|
|
for (const auto &ao : outputs) {
|
|
auto *mixer = ao->GetMixer();
|
|
|
|
if (mixer != nullptr &&
|
|
(&mixer->plugin == &software_mixer_plugin ||
|
|
&mixer->plugin == &null_mixer_plugin))
|
|
mixer_set_volume(mixer, volume);
|
|
}
|
|
}
|