output/MultipleOutputs: SetVolume() throws on error
This reveals more about the nature of an error instead of just returning "problems setting volume".
This commit is contained in:
+45
-13
@@ -73,42 +73,74 @@ MultipleOutputs::GetVolume() const noexcept
|
||||
return total / ok;
|
||||
}
|
||||
|
||||
static bool
|
||||
output_mixer_set_volume(AudioOutputControl &ao, unsigned volume) noexcept
|
||||
enum class SetVolumeResult {
|
||||
NO_MIXER,
|
||||
DISABLED,
|
||||
ERROR,
|
||||
OK,
|
||||
};
|
||||
|
||||
static SetVolumeResult
|
||||
output_mixer_set_volume(AudioOutputControl &ao, unsigned volume)
|
||||
{
|
||||
assert(volume <= 100);
|
||||
|
||||
auto *mixer = ao.GetMixer();
|
||||
if (mixer == nullptr)
|
||||
return false;
|
||||
return SetVolumeResult::NO_MIXER;
|
||||
|
||||
/* software mixers are always updated, even if they are
|
||||
disabled */
|
||||
if (!ao.IsReallyEnabled() && !mixer->IsPlugin(software_mixer_plugin))
|
||||
return false;
|
||||
return SetVolumeResult::DISABLED;
|
||||
|
||||
try {
|
||||
mixer_set_volume(mixer, volume);
|
||||
return true;
|
||||
return SetVolumeResult::OK;
|
||||
} catch (...) {
|
||||
FmtError(mixer_domain,
|
||||
"Failed to set mixer for '{}': {}",
|
||||
ao.GetName(), std::current_exception());
|
||||
return false;
|
||||
std::throw_with_nested(std::runtime_error(fmt::format("Failed to set mixer for '{}'",
|
||||
ao.GetName())));
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MultipleOutputs::SetVolume(unsigned volume) noexcept
|
||||
void
|
||||
MultipleOutputs::SetVolume(unsigned volume)
|
||||
{
|
||||
assert(volume <= 100);
|
||||
|
||||
bool success = false;
|
||||
for (const auto &ao : outputs)
|
||||
success = output_mixer_set_volume(*ao, volume)
|
||||
|| success;
|
||||
SetVolumeResult result = SetVolumeResult::NO_MIXER;
|
||||
std::exception_ptr error;
|
||||
|
||||
return success;
|
||||
for (const auto &ao : outputs) {
|
||||
try {
|
||||
auto r = output_mixer_set_volume(*ao, volume);
|
||||
if (r > result)
|
||||
result = r;
|
||||
} catch (...) {
|
||||
/* remember the first error */
|
||||
if (!error) {
|
||||
error = std::current_exception();
|
||||
result = SetVolumeResult::ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (result) {
|
||||
case SetVolumeResult::NO_MIXER:
|
||||
throw std::runtime_error{"No mixer"};
|
||||
|
||||
case SetVolumeResult::DISABLED:
|
||||
throw std::runtime_error{"All outputs are disabled"};
|
||||
|
||||
case SetVolumeResult::ERROR:
|
||||
std::rethrow_exception(error);
|
||||
|
||||
case SetVolumeResult::OK:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
|
||||
@@ -71,16 +71,16 @@ software_volume_change(MultipleOutputs &outputs, unsigned volume)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
static void
|
||||
hardware_volume_change(MultipleOutputs &outputs, unsigned volume)
|
||||
{
|
||||
/* reset the cache */
|
||||
last_hardware_volume = -1;
|
||||
|
||||
return outputs.SetVolume(volume);
|
||||
outputs.SetVolume(volume);
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
volume_level_change(MultipleOutputs &outputs, unsigned volume)
|
||||
{
|
||||
assert(volume <= 100);
|
||||
@@ -89,7 +89,7 @@ volume_level_change(MultipleOutputs &outputs, unsigned volume)
|
||||
|
||||
idle_add(IDLE_MIXER);
|
||||
|
||||
return hardware_volume_change(outputs, volume);
|
||||
hardware_volume_change(outputs, volume);
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -30,7 +30,10 @@ InvalidateHardwareVolume() noexcept;
|
||||
int
|
||||
volume_level_get(const MultipleOutputs &outputs) noexcept;
|
||||
|
||||
bool
|
||||
/**
|
||||
* Throws on error.
|
||||
*/
|
||||
void
|
||||
volume_level_change(MultipleOutputs &outputs, unsigned volume);
|
||||
|
||||
bool
|
||||
|
||||
Reference in New Issue
Block a user