Commit e7d32722 authored by Max Kellermann's avatar Max Kellermann

mixer: migrate to C++ exceptions

parent ae1eb9cc
...@@ -158,9 +158,11 @@ ReplayGainFilter::Update() ...@@ -158,9 +158,11 @@ ReplayGainFilter::Update()
if (_volume > 100) if (_volume > 100)
_volume = 100; _volume = 100;
Error error; try {
if (!mixer_set_volume(mixer, _volume, error)) mixer_set_volume(mixer, _volume);
LogError(error, "Failed to update hardware mixer"); } catch (const std::runtime_error &e) {
LogError(e, "Failed to update hardware mixer");
}
} else } else
pv.SetVolume(volume); pv.SetVolume(volume);
} }
......
...@@ -24,9 +24,10 @@ ...@@ -24,9 +24,10 @@
#include "MixerList.hxx" #include "MixerList.hxx"
#include "output/Internal.hxx" #include "output/Internal.hxx"
#include "pcm/Volume.hxx" #include "pcm/Volume.hxx"
#include "util/Error.hxx"
#include "Log.hxx" #include "Log.hxx"
#include <stdexcept>
#include <assert.h> #include <assert.h>
static int static int
...@@ -39,14 +40,14 @@ output_mixer_get_volume(const AudioOutput &ao) ...@@ -39,14 +40,14 @@ output_mixer_get_volume(const AudioOutput &ao)
if (mixer == nullptr) if (mixer == nullptr)
return -1; return -1;
Error error; try {
int volume = mixer_get_volume(mixer, error); return mixer_get_volume(mixer);
if (volume < 0 && error.IsDefined()) } catch (const std::runtime_error &e) {
FormatError(error, FormatError(e,
"Failed to read mixer for '%s'", "Failed to read mixer for '%s'",
ao.name); ao.name);
return -1;
return volume; }
} }
int int
...@@ -81,14 +82,15 @@ output_mixer_set_volume(AudioOutput &ao, unsigned volume) ...@@ -81,14 +82,15 @@ output_mixer_set_volume(AudioOutput &ao, unsigned volume)
if (mixer == nullptr) if (mixer == nullptr)
return false; return false;
Error error; try {
bool success = mixer_set_volume(mixer, volume, error); mixer_set_volume(mixer, volume);
if (!success && error.IsDefined()) return true;
FormatError(error, } catch (const std::runtime_error &e) {
FormatError(e,
"Failed to set mixer for '%s'", "Failed to set mixer for '%s'",
ao.name); ao.name);
return false;
return success; }
} }
bool bool
...@@ -114,7 +116,7 @@ output_mixer_get_software_volume(const AudioOutput &ao) ...@@ -114,7 +116,7 @@ output_mixer_get_software_volume(const AudioOutput &ao)
if (mixer == nullptr || !mixer->IsPlugin(software_mixer_plugin)) if (mixer == nullptr || !mixer->IsPlugin(software_mixer_plugin))
return -1; return -1;
return mixer_get_volume(mixer, IgnoreError()); return mixer_get_volume(mixer);
} }
int int
...@@ -148,6 +150,6 @@ MultipleOutputs::SetSoftwareVolume(unsigned volume) ...@@ -148,6 +150,6 @@ MultipleOutputs::SetSoftwareVolume(unsigned volume)
if (mixer != nullptr && if (mixer != nullptr &&
(&mixer->plugin == &software_mixer_plugin || (&mixer->plugin == &software_mixer_plugin ||
&mixer->plugin == &null_mixer_plugin)) &mixer->plugin == &null_mixer_plugin))
mixer_set_volume(mixer, volume, IgnoreError()); mixer_set_volume(mixer, volume);
} }
} }
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include "config.h" #include "config.h"
#include "MixerControl.hxx" #include "MixerControl.hxx"
#include "MixerInternal.hxx" #include "MixerInternal.hxx"
#include "util/Error.hxx"
#include <assert.h> #include <assert.h>
...@@ -28,10 +27,9 @@ Mixer * ...@@ -28,10 +27,9 @@ Mixer *
mixer_new(EventLoop &event_loop, mixer_new(EventLoop &event_loop,
const MixerPlugin &plugin, AudioOutput &ao, const MixerPlugin &plugin, AudioOutput &ao,
MixerListener &listener, MixerListener &listener,
const ConfigBlock &block, const ConfigBlock &block)
Error &error)
{ {
Mixer *mixer = plugin.init(event_loop, ao, listener, block, error); Mixer *mixer = plugin.init(event_loop, ao, listener, block);
assert(mixer == nullptr || mixer->IsPlugin(plugin)); assert(mixer == nullptr || mixer->IsPlugin(plugin));
...@@ -50,20 +48,24 @@ mixer_free(Mixer *mixer) ...@@ -50,20 +48,24 @@ mixer_free(Mixer *mixer)
delete mixer; delete mixer;
} }
bool void
mixer_open(Mixer *mixer, Error &error) mixer_open(Mixer *mixer)
{ {
bool success;
assert(mixer != nullptr); assert(mixer != nullptr);
const ScopeLock protect(mixer->mutex); const ScopeLock protect(mixer->mutex);
success = mixer->open || (mixer->open = mixer->Open(error)); if (mixer->open)
return;
mixer->failed = !success;
try {
return success; mixer->Open();
mixer->open = true;
mixer->failed = false;
} catch (...) {
mixer->failed = true;
throw;
}
} }
static void static void
...@@ -109,39 +111,41 @@ mixer_failed(Mixer *mixer) ...@@ -109,39 +111,41 @@ mixer_failed(Mixer *mixer)
} }
int int
mixer_get_volume(Mixer *mixer, Error &error) mixer_get_volume(Mixer *mixer)
{ {
int volume; int volume;
assert(mixer != nullptr); assert(mixer != nullptr);
if (mixer->plugin.global && !mixer->failed && if (mixer->plugin.global && !mixer->failed)
!mixer_open(mixer, error)) mixer_open(mixer);
return -1;
const ScopeLock protect(mixer->mutex); const ScopeLock protect(mixer->mutex);
if (mixer->open) { if (mixer->open) {
volume = mixer->GetVolume(error); try {
if (volume < 0 && error.IsDefined()) volume = mixer->GetVolume();
} catch (...) {
mixer_failed(mixer); mixer_failed(mixer);
throw;
}
} else } else
volume = -1; volume = -1;
return volume; return volume;
} }
bool void
mixer_set_volume(Mixer *mixer, unsigned volume, Error &error) mixer_set_volume(Mixer *mixer, unsigned volume)
{ {
assert(mixer != nullptr); assert(mixer != nullptr);
assert(volume <= 100); assert(volume <= 100);
if (mixer->plugin.global && !mixer->failed && if (mixer->plugin.global && !mixer->failed)
!mixer_open(mixer, error)) mixer_open(mixer);
return false;
const ScopeLock protect(mixer->mutex); const ScopeLock protect(mixer->mutex);
return mixer->open && mixer->SetVolume(volume, error); if (mixer->open)
mixer->SetVolume(volume);
} }
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#ifndef MPD_MIXER_CONTROL_HXX #ifndef MPD_MIXER_CONTROL_HXX
#define MPD_MIXER_CONTROL_HXX #define MPD_MIXER_CONTROL_HXX
class Error;
class Mixer; class Mixer;
class EventLoop; class EventLoop;
struct AudioOutput; struct AudioOutput;
...@@ -33,17 +32,22 @@ struct MixerPlugin; ...@@ -33,17 +32,22 @@ struct MixerPlugin;
class MixerListener; class MixerListener;
struct ConfigBlock; struct ConfigBlock;
/**
* Throws std::runtime_error on error.
*/
Mixer * Mixer *
mixer_new(EventLoop &event_loop, const MixerPlugin &plugin, AudioOutput &ao, mixer_new(EventLoop &event_loop, const MixerPlugin &plugin, AudioOutput &ao,
MixerListener &listener, MixerListener &listener,
const ConfigBlock &block, const ConfigBlock &block);
Error &error);
void void
mixer_free(Mixer *mixer); mixer_free(Mixer *mixer);
bool /**
mixer_open(Mixer *mixer, Error &error); * Throws std::runtime_error on error.
*/
void
mixer_open(Mixer *mixer);
void void
mixer_close(Mixer *mixer); mixer_close(Mixer *mixer);
...@@ -55,10 +59,16 @@ mixer_close(Mixer *mixer); ...@@ -55,10 +59,16 @@ mixer_close(Mixer *mixer);
void void
mixer_auto_close(Mixer *mixer); mixer_auto_close(Mixer *mixer);
/**
* Throws std::runtime_error on error.
*/
int int
mixer_get_volume(Mixer *mixer, Error &error); mixer_get_volume(Mixer *mixer);
bool /**
mixer_set_volume(Mixer *mixer, unsigned volume, Error &error); * Throws std::runtime_error on error.
*/
void
mixer_set_volume(Mixer *mixer, unsigned volume);
#endif #endif
...@@ -67,9 +67,9 @@ public: ...@@ -67,9 +67,9 @@ public:
/** /**
* Open mixer device * Open mixer device
* *
* @return true on success, false on error * Throws std::runtime_error on error.
*/ */
virtual bool Open(Error &error) = 0; virtual void Open() = 0;
/** /**
* Close mixer device * Close mixer device
...@@ -79,19 +79,22 @@ public: ...@@ -79,19 +79,22 @@ public:
/** /**
* Reads the current volume. * Reads the current volume.
* *
* Throws std::runtime_error on error.
*
* @return the current volume (0..100 including) or -1 if * @return the current volume (0..100 including) or -1 if
* unavailable or on error (error set, mixer will be closed) * unavailable
*/ */
gcc_pure gcc_pure
virtual int GetVolume(Error &error) = 0; virtual int GetVolume() = 0;
/** /**
* Sets the volume. * Sets the volume.
* *
* @param volume the new volume (0..100 including) @return * Throws std::runtime_error on error.
* true on success, false on error *
* @param volume the new volume (0..100 including)
*/ */
virtual bool SetVolume(unsigned volume, Error &error) = 0; virtual void SetVolume(unsigned volume) = 0;
}; };
#endif #endif
...@@ -32,22 +32,20 @@ struct AudioOutput; ...@@ -32,22 +32,20 @@ struct AudioOutput;
class Mixer; class Mixer;
class MixerListener; class MixerListener;
class EventLoop; class EventLoop;
class Error;
struct MixerPlugin { struct MixerPlugin {
/** /**
* Alocates and configures a mixer device. * Alocates and configures a mixer device.
* *
* Throws std::runtime_error on error.
*
* @param ao the associated AudioOutput * @param ao the associated AudioOutput
* @param param the configuration section * @param param the configuration section
* @param error_r location to store the error occurring, or * @return a mixer object
* nullptr to ignore errors
* @return a mixer object, or nullptr on error
*/ */
Mixer *(*init)(EventLoop &event_loop, AudioOutput &ao, Mixer *(*init)(EventLoop &event_loop, AudioOutput &ao,
MixerListener &listener, MixerListener &listener,
const ConfigBlock &block, const ConfigBlock &block);
Error &error);
/** /**
* If true, then the mixer is automatically opened, even if * If true, then the mixer is automatically opened, even if
......
...@@ -26,8 +26,8 @@ ...@@ -26,8 +26,8 @@
#include "util/ASCII.hxx" #include "util/ASCII.hxx"
#include "util/ReusableArray.hxx" #include "util/ReusableArray.hxx"
#include "util/Clamp.hxx" #include "util/Clamp.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
#include "util/RuntimeError.hxx"
#include "Log.hxx" #include "Log.hxx"
#include <algorithm> #include <algorithm>
...@@ -82,13 +82,13 @@ public: ...@@ -82,13 +82,13 @@ public:
virtual ~AlsaMixer(); virtual ~AlsaMixer();
void Configure(const ConfigBlock &block); void Configure(const ConfigBlock &block);
bool Setup(Error &error); void Setup();
/* virtual methods from class Mixer */ /* virtual methods from class Mixer */
virtual bool Open(Error &error) override; void Open() override;
virtual void Close() override; void Close() override;
virtual int GetVolume(Error &error) override; int GetVolume() override;
virtual bool SetVolume(unsigned volume, Error &error) override; void SetVolume(unsigned volume) override;
}; };
static constexpr Domain alsa_mixer_domain("alsa_mixer"); static constexpr Domain alsa_mixer_domain("alsa_mixer");
...@@ -148,8 +148,11 @@ alsa_mixer_elem_callback(snd_mixer_elem_t *elem, unsigned mask) ...@@ -148,8 +148,11 @@ alsa_mixer_elem_callback(snd_mixer_elem_t *elem, unsigned mask)
snd_mixer_elem_get_callback_private(elem); snd_mixer_elem_get_callback_private(elem);
if (mask & SND_CTL_EVENT_MASK_VALUE) { if (mask & SND_CTL_EVENT_MASK_VALUE) {
int volume = mixer.GetVolume(IgnoreError()); try {
mixer.listener.OnMixerVolumeChanged(mixer, volume); int volume = mixer.GetVolume();
mixer.listener.OnMixerVolumeChanged(mixer, volume);
} catch (const std::runtime_error &) {
}
} }
return 0; return 0;
...@@ -174,8 +177,7 @@ AlsaMixer::Configure(const ConfigBlock &block) ...@@ -174,8 +177,7 @@ AlsaMixer::Configure(const ConfigBlock &block)
static Mixer * static Mixer *
alsa_mixer_init(EventLoop &event_loop, gcc_unused AudioOutput &ao, alsa_mixer_init(EventLoop &event_loop, gcc_unused AudioOutput &ao,
MixerListener &listener, MixerListener &listener,
const ConfigBlock &block, const ConfigBlock &block)
gcc_unused Error &error)
{ {
AlsaMixer *am = new AlsaMixer(event_loop, listener); AlsaMixer *am = new AlsaMixer(event_loop, listener);
am->Configure(block); am->Configure(block);
...@@ -205,39 +207,26 @@ alsa_mixer_lookup_elem(snd_mixer_t *handle, const char *name, unsigned idx) ...@@ -205,39 +207,26 @@ alsa_mixer_lookup_elem(snd_mixer_t *handle, const char *name, unsigned idx)
return nullptr; return nullptr;
} }
inline bool inline void
AlsaMixer::Setup(Error &error) AlsaMixer::Setup()
{ {
int err; int err;
if ((err = snd_mixer_attach(handle, device)) < 0) { if ((err = snd_mixer_attach(handle, device)) < 0)
error.Format(alsa_mixer_domain, err, throw FormatRuntimeError("failed to attach to %s: %s",
"failed to attach to %s: %s", device, snd_strerror(err));
device, snd_strerror(err));
return false;
}
if ((err = snd_mixer_selem_register(handle, nullptr, if ((err = snd_mixer_selem_register(handle, nullptr, nullptr)) < 0)
nullptr)) < 0) { throw FormatRuntimeError("snd_mixer_selem_register() failed: %s",
error.Format(alsa_mixer_domain, err, snd_strerror(err));
"snd_mixer_selem_register() failed: %s",
snd_strerror(err));
return false;
}
if ((err = snd_mixer_load(handle)) < 0) { if ((err = snd_mixer_load(handle)) < 0)
error.Format(alsa_mixer_domain, err, throw FormatRuntimeError("snd_mixer_load() failed: %s\n",
"snd_mixer_load() failed: %s\n", snd_strerror(err));
snd_strerror(err));
return false;
}
elem = alsa_mixer_lookup_elem(handle, control, index); elem = alsa_mixer_lookup_elem(handle, control, index);
if (elem == nullptr) { if (elem == nullptr)
error.Format(alsa_mixer_domain, 0, throw FormatRuntimeError("no such mixer control: %s", control);
"no such mixer control: %s", control);
return false;
}
snd_mixer_selem_get_playback_volume_range(elem, &volume_min, snd_mixer_selem_get_playback_volume_range(elem, &volume_min,
&volume_max); &volume_max);
...@@ -246,33 +235,29 @@ AlsaMixer::Setup(Error &error) ...@@ -246,33 +235,29 @@ AlsaMixer::Setup(Error &error)
snd_mixer_elem_set_callback(elem, alsa_mixer_elem_callback); snd_mixer_elem_set_callback(elem, alsa_mixer_elem_callback);
monitor = new AlsaMixerMonitor(event_loop, handle); monitor = new AlsaMixerMonitor(event_loop, handle);
return true;
} }
inline bool void
AlsaMixer::Open(Error &error) AlsaMixer::Open()
{ {
int err; int err;
volume_set = -1; volume_set = -1;
err = snd_mixer_open(&handle, 0); err = snd_mixer_open(&handle, 0);
if (err < 0) { if (err < 0)
error.Format(alsa_mixer_domain, err, throw FormatRuntimeError("snd_mixer_open() failed: %s",
"snd_mixer_open() failed: %s", snd_strerror(err)); snd_strerror(err));
return false;
}
if (!Setup(error)) { try {
Setup();
} catch (...) {
snd_mixer_close(handle); snd_mixer_close(handle);
return false; throw;
} }
return true;
} }
inline void void
AlsaMixer::Close() AlsaMixer::Close()
{ {
assert(handle != nullptr); assert(handle != nullptr);
...@@ -283,8 +268,8 @@ AlsaMixer::Close() ...@@ -283,8 +268,8 @@ AlsaMixer::Close()
snd_mixer_close(handle); snd_mixer_close(handle);
} }
inline int int
AlsaMixer::GetVolume(Error &error) AlsaMixer::GetVolume()
{ {
int err; int err;
int ret; int ret;
...@@ -293,22 +278,16 @@ AlsaMixer::GetVolume(Error &error) ...@@ -293,22 +278,16 @@ AlsaMixer::GetVolume(Error &error)
assert(handle != nullptr); assert(handle != nullptr);
err = snd_mixer_handle_events(handle); err = snd_mixer_handle_events(handle);
if (err < 0) { if (err < 0)
error.Format(alsa_mixer_domain, err, throw FormatRuntimeError("snd_mixer_handle_events() failed: %s",
"snd_mixer_handle_events() failed: %s", snd_strerror(err));
snd_strerror(err));
return false;
}
err = snd_mixer_selem_get_playback_volume(elem, err = snd_mixer_selem_get_playback_volume(elem,
SND_MIXER_SCHN_FRONT_LEFT, SND_MIXER_SCHN_FRONT_LEFT,
&level); &level);
if (err < 0) { if (err < 0)
error.Format(alsa_mixer_domain, err, throw FormatRuntimeError("failed to read ALSA volume: %s",
"failed to read ALSA volume: %s", snd_strerror(err));
snd_strerror(err));
return false;
}
ret = ((volume_set / 100.0) * (volume_max - volume_min) ret = ((volume_set / 100.0) * (volume_max - volume_min)
+ volume_min) + 0.5; + volume_min) + 0.5;
...@@ -322,8 +301,8 @@ AlsaMixer::GetVolume(Error &error) ...@@ -322,8 +301,8 @@ AlsaMixer::GetVolume(Error &error)
return ret; return ret;
} }
inline bool void
AlsaMixer::SetVolume(unsigned volume, Error &error) AlsaMixer::SetVolume(unsigned volume)
{ {
float vol; float vol;
long level; long level;
...@@ -340,14 +319,9 @@ AlsaMixer::SetVolume(unsigned volume, Error &error) ...@@ -340,14 +319,9 @@ AlsaMixer::SetVolume(unsigned volume, Error &error)
level = Clamp(level, volume_min, volume_max); level = Clamp(level, volume_min, volume_max);
err = snd_mixer_selem_set_playback_volume_all(elem, level); err = snd_mixer_selem_set_playback_volume_all(elem, level);
if (err < 0) { if (err < 0)
error.Format(alsa_mixer_domain, err, throw FormatRuntimeError("failed to set ALSA volume: %s",
"failed to set ALSA volume: %s", snd_strerror(err));
snd_strerror(err));
return false;
}
return true;
} }
const MixerPlugin alsa_mixer_plugin = { const MixerPlugin alsa_mixer_plugin = {
......
...@@ -34,20 +34,18 @@ public: ...@@ -34,20 +34,18 @@ public:
} }
/* virtual methods from class Mixer */ /* virtual methods from class Mixer */
bool Open(gcc_unused Error &error) override { void Open() override {
return true;
} }
void Close() override { void Close() override {
} }
int GetVolume(gcc_unused Error &error) override { int GetVolume() override {
return volume; return volume;
} }
bool SetVolume(unsigned _volume, gcc_unused Error &error) override { void SetVolume(unsigned _volume) override {
volume = _volume; volume = _volume;
return true;
} }
}; };
...@@ -55,8 +53,7 @@ static Mixer * ...@@ -55,8 +53,7 @@ static Mixer *
null_mixer_init(gcc_unused EventLoop &event_loop, null_mixer_init(gcc_unused EventLoop &event_loop,
gcc_unused AudioOutput &ao, gcc_unused AudioOutput &ao,
MixerListener &listener, MixerListener &listener,
gcc_unused const ConfigBlock &block, gcc_unused const ConfigBlock &block)
gcc_unused Error &error)
{ {
return new NullMixer(listener); return new NullMixer(listener);
} }
......
...@@ -21,9 +21,10 @@ ...@@ -21,9 +21,10 @@
#include "mixer/MixerInternal.hxx" #include "mixer/MixerInternal.hxx"
#include "config/Block.hxx" #include "config/Block.hxx"
#include "system/fd_util.h" #include "system/fd_util.h"
#include "system/Error.hxx"
#include "util/ASCII.hxx" #include "util/ASCII.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
#include "util/RuntimeError.hxx"
#include "Log.hxx" #include "Log.hxx"
#include <assert.h> #include <assert.h>
...@@ -49,16 +50,18 @@ class OssMixer final : public Mixer { ...@@ -49,16 +50,18 @@ class OssMixer final : public Mixer {
int volume_control; int volume_control;
public: public:
OssMixer(MixerListener &_listener) OssMixer(MixerListener &_listener, const ConfigBlock &block)
:Mixer(oss_mixer_plugin, _listener) {} :Mixer(oss_mixer_plugin, _listener) {
Configure(block);
}
bool Configure(const ConfigBlock &block, Error &error); void Configure(const ConfigBlock &block);
/* virtual methods from class Mixer */ /* virtual methods from class Mixer */
virtual bool Open(Error &error) override; void Open() override;
virtual void Close() override; void Close() override;
virtual int GetVolume(Error &error) override; int GetVolume() override;
virtual bool SetVolume(unsigned volume, Error &error) override; void SetVolume(unsigned volume) override;
}; };
static constexpr Domain oss_mixer_domain("oss_mixer"); static constexpr Domain oss_mixer_domain("oss_mixer");
...@@ -78,39 +81,27 @@ oss_find_mixer(const char *name) ...@@ -78,39 +81,27 @@ oss_find_mixer(const char *name)
return -1; return -1;
} }
inline bool inline void
OssMixer::Configure(const ConfigBlock &block, Error &error) OssMixer::Configure(const ConfigBlock &block)
{ {
device = block.GetBlockValue("mixer_device", VOLUME_MIXER_OSS_DEFAULT); device = block.GetBlockValue("mixer_device", VOLUME_MIXER_OSS_DEFAULT);
control = block.GetBlockValue("mixer_control"); control = block.GetBlockValue("mixer_control");
if (control != NULL) { if (control != NULL) {
volume_control = oss_find_mixer(control); volume_control = oss_find_mixer(control);
if (volume_control < 0) { if (volume_control < 0)
error.Format(oss_mixer_domain, 0, throw FormatRuntimeError("no such mixer control: %s",
"no such mixer control: %s", control); control);
return false;
}
} else } else
volume_control = SOUND_MIXER_PCM; volume_control = SOUND_MIXER_PCM;
return true;
} }
static Mixer * static Mixer *
oss_mixer_init(gcc_unused EventLoop &event_loop, gcc_unused AudioOutput &ao, oss_mixer_init(gcc_unused EventLoop &event_loop, gcc_unused AudioOutput &ao,
MixerListener &listener, MixerListener &listener,
const ConfigBlock &block, const ConfigBlock &block)
Error &error)
{ {
OssMixer *om = new OssMixer(listener); return new OssMixer(listener, block);
if (!om->Configure(block, error)) {
delete om;
return nullptr;
}
return om;
} }
void void
...@@ -121,38 +112,32 @@ OssMixer::Close() ...@@ -121,38 +112,32 @@ OssMixer::Close()
close(device_fd); close(device_fd);
} }
bool void
OssMixer::Open(Error &error) OssMixer::Open()
{ {
device_fd = open_cloexec(device, O_RDONLY, 0); device_fd = open_cloexec(device, O_RDONLY, 0);
if (device_fd < 0) { if (device_fd < 0)
error.FormatErrno("failed to open %s", device); throw FormatErrno("failed to open %s", device);
return false;
}
if (control) { try {
int devmask = 0; if (control) {
int devmask = 0;
if (ioctl(device_fd, SOUND_MIXER_READ_DEVMASK, &devmask) < 0) { if (ioctl(device_fd, SOUND_MIXER_READ_DEVMASK, &devmask) < 0)
error.SetErrno("READ_DEVMASK failed"); throw MakeErrno("READ_DEVMASK failed");
Close();
return false;
}
if (((1 << volume_control) & devmask) == 0) { if (((1 << volume_control) & devmask) == 0)
error.Format(oss_mixer_domain, 0, throw FormatErrno("mixer control \"%s\" not usable",
"mixer control \"%s\" not usable", control);
control);
Close();
return false;
} }
} catch (...) {
Close();
throw;
} }
return true;
} }
int int
OssMixer::GetVolume(Error &error) OssMixer::GetVolume()
{ {
int left, right, level; int left, right, level;
int ret; int ret;
...@@ -160,10 +145,8 @@ OssMixer::GetVolume(Error &error) ...@@ -160,10 +145,8 @@ OssMixer::GetVolume(Error &error)
assert(device_fd >= 0); assert(device_fd >= 0);
ret = ioctl(device_fd, MIXER_READ(volume_control), &level); ret = ioctl(device_fd, MIXER_READ(volume_control), &level);
if (ret < 0) { if (ret < 0)
error.SetErrno("failed to read OSS volume"); throw MakeErrno("failed to read OSS volume");
return false;
}
left = level & 0xff; left = level & 0xff;
right = (level & 0xff00) >> 8; right = (level & 0xff00) >> 8;
...@@ -177,24 +160,18 @@ OssMixer::GetVolume(Error &error) ...@@ -177,24 +160,18 @@ OssMixer::GetVolume(Error &error)
return left; return left;
} }
bool void
OssMixer::SetVolume(unsigned volume, Error &error) OssMixer::SetVolume(unsigned volume)
{ {
int level; int level;
int ret;
assert(device_fd >= 0); assert(device_fd >= 0);
assert(volume <= 100); assert(volume <= 100);
level = (volume << 8) + volume; level = (volume << 8) + volume;
ret = ioctl(device_fd, MIXER_WRITE(volume_control), &level); if (ioctl(device_fd, MIXER_WRITE(volume_control), &level) < 0)
if (ret < 0) { throw MakeErrno("failed to set OSS volume");
error.SetErrno("failed to set OSS volume");
return false;
}
return true;
} }
const MixerPlugin oss_mixer_plugin = { const MixerPlugin oss_mixer_plugin = {
......
...@@ -25,13 +25,14 @@ ...@@ -25,13 +25,14 @@
#include "mixer/MixerInternal.hxx" #include "mixer/MixerInternal.hxx"
#include "mixer/Listener.hxx" #include "mixer/Listener.hxx"
#include "output/plugins/PulseOutputPlugin.hxx" #include "output/plugins/PulseOutputPlugin.hxx"
#include "util/Error.hxx"
#include <pulse/context.h> #include <pulse/context.h>
#include <pulse/introspect.h> #include <pulse/introspect.h>
#include <pulse/stream.h> #include <pulse/stream.h>
#include <pulse/subscribe.h> #include <pulse/subscribe.h>
#include <stdexcept>
#include <assert.h> #include <assert.h>
class PulseMixer final : public Mixer { class PulseMixer final : public Mixer {
...@@ -52,18 +53,17 @@ public: ...@@ -52,18 +53,17 @@ public:
void Offline(); void Offline();
void VolumeCallback(const pa_sink_input_info *i, int eol); void VolumeCallback(const pa_sink_input_info *i, int eol);
void Update(pa_context *context, pa_stream *stream); void Update(pa_context *context, pa_stream *stream);
int GetVolumeInternal(Error &error); int GetVolumeInternal();
/* virtual methods from class Mixer */ /* virtual methods from class Mixer */
bool Open(gcc_unused Error &error) override { void Open() override {
return true;
} }
void Close() override { void Close() override {
} }
int GetVolume(Error &error) override; int GetVolume() override;
bool SetVolume(unsigned volume, Error &error) override; void SetVolume(unsigned volume) override;
}; };
void void
...@@ -91,7 +91,7 @@ PulseMixer::VolumeCallback(const pa_sink_input_info *i, int eol) ...@@ -91,7 +91,7 @@ PulseMixer::VolumeCallback(const pa_sink_input_info *i, int eol)
online = true; online = true;
volume = i->volume; volume = i->volume;
listener.OnMixerVolumeChanged(*this, GetVolumeInternal(IgnoreError())); listener.OnMixerVolumeChanged(*this, GetVolumeInternal());
} }
/** /**
...@@ -163,8 +163,7 @@ pulse_mixer_on_change(PulseMixer &pm, ...@@ -163,8 +163,7 @@ pulse_mixer_on_change(PulseMixer &pm,
static Mixer * static Mixer *
pulse_mixer_init(gcc_unused EventLoop &event_loop, AudioOutput &ao, pulse_mixer_init(gcc_unused EventLoop &event_loop, AudioOutput &ao,
MixerListener &listener, MixerListener &listener,
gcc_unused const ConfigBlock &block, gcc_unused const ConfigBlock &block)
gcc_unused Error &error)
{ {
PulseOutput &po = (PulseOutput &)ao; PulseOutput &po = (PulseOutput &)ao;
PulseMixer *pm = new PulseMixer(po, listener); PulseMixer *pm = new PulseMixer(po, listener);
...@@ -180,42 +179,37 @@ PulseMixer::~PulseMixer() ...@@ -180,42 +179,37 @@ PulseMixer::~PulseMixer()
} }
int int
PulseMixer::GetVolume(gcc_unused Error &error) PulseMixer::GetVolume()
{ {
Pulse::LockGuard lock(pulse_output_get_mainloop(output)); Pulse::LockGuard lock(pulse_output_get_mainloop(output));
return GetVolumeInternal(error); return GetVolumeInternal();
} }
/** /**
* Pulse mainloop lock must be held by caller * Pulse mainloop lock must be held by caller
*/ */
int int
PulseMixer::GetVolumeInternal(gcc_unused Error &error) PulseMixer::GetVolumeInternal()
{ {
return online ? return online ?
(int)((100 * (pa_cvolume_avg(&volume) + 1)) / PA_VOLUME_NORM) (int)((100 * (pa_cvolume_avg(&volume) + 1)) / PA_VOLUME_NORM)
: -1; : -1;
} }
bool void
PulseMixer::SetVolume(unsigned new_volume, Error &error) PulseMixer::SetVolume(unsigned new_volume)
{ {
Pulse::LockGuard lock(pulse_output_get_mainloop(output)); Pulse::LockGuard lock(pulse_output_get_mainloop(output));
if (!online) { if (!online)
error.Set(pulse_domain, "disconnected"); throw std::runtime_error("disconnected");
return false;
}
struct pa_cvolume cvolume; struct pa_cvolume cvolume;
pa_cvolume_set(&cvolume, volume.channels, pa_cvolume_set(&cvolume, volume.channels,
(new_volume * PA_VOLUME_NORM + 50) / 100); (new_volume * PA_VOLUME_NORM + 50) / 100);
bool success = pulse_output_set_volume(output, &cvolume, error); pulse_output_set_volume(output, &cvolume);
if (success) volume = cvolume;
volume = cvolume;
return success;
} }
const MixerPlugin pulse_mixer_plugin = { const MixerPlugin pulse_mixer_plugin = {
......
...@@ -34,36 +34,34 @@ public: ...@@ -34,36 +34,34 @@ public:
self(_output) {} self(_output) {}
/* virtual methods from class Mixer */ /* virtual methods from class Mixer */
virtual bool Open(gcc_unused Error &error) override { void Open() override {
return true;
} }
virtual void Close() override { virtual void Close() override {
} }
virtual int GetVolume(Error &error) override; int GetVolume() override;
virtual bool SetVolume(unsigned volume, Error &error) override; void SetVolume(unsigned volume) override;
}; };
static Mixer * static Mixer *
roar_mixer_init(gcc_unused EventLoop &event_loop, AudioOutput &ao, roar_mixer_init(gcc_unused EventLoop &event_loop, AudioOutput &ao,
MixerListener &listener, MixerListener &listener,
gcc_unused const ConfigBlock &block, gcc_unused const ConfigBlock &block)
gcc_unused Error &error)
{ {
return new RoarMixer((RoarOutput &)ao, listener); return new RoarMixer((RoarOutput &)ao, listener);
} }
int int
RoarMixer::GetVolume(gcc_unused Error &error) RoarMixer::GetVolume()
{ {
return roar_output_get_volume(self); return roar_output_get_volume(self);
} }
bool void
RoarMixer::SetVolume(unsigned volume, gcc_unused Error &error) RoarMixer::SetVolume(unsigned volume)
{ {
return roar_output_set_volume(self, volume); roar_output_set_volume(self, volume);
} }
const MixerPlugin roar_mixer_plugin = { const MixerPlugin roar_mixer_plugin = {
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#include "filter/plugins/VolumeFilterPlugin.hxx" #include "filter/plugins/VolumeFilterPlugin.hxx"
#include "pcm/Volume.hxx" #include "pcm/Volume.hxx"
#include "config/Block.hxx" #include "config/Block.hxx"
#include "util/Error.hxx"
#include <assert.h> #include <assert.h>
#include <math.h> #include <math.h>
...@@ -48,26 +47,24 @@ public: ...@@ -48,26 +47,24 @@ public:
void SetFilter(Filter *_filter); void SetFilter(Filter *_filter);
/* virtual methods from class Mixer */ /* virtual methods from class Mixer */
virtual bool Open(gcc_unused Error &error) override { void Open() override {
return true;
} }
virtual void Close() override { virtual void Close() override {
} }
virtual int GetVolume(gcc_unused Error &error) override { int GetVolume() override {
return volume; return volume;
} }
virtual bool SetVolume(unsigned volume, Error &error) override; void SetVolume(unsigned volume) override;
}; };
static Mixer * static Mixer *
software_mixer_init(gcc_unused EventLoop &event_loop, software_mixer_init(gcc_unused EventLoop &event_loop,
gcc_unused AudioOutput &ao, gcc_unused AudioOutput &ao,
MixerListener &listener, MixerListener &listener,
gcc_unused const ConfigBlock &block, gcc_unused const ConfigBlock &block)
gcc_unused Error &error)
{ {
return new SoftwareMixer(listener); return new SoftwareMixer(listener);
} }
...@@ -87,8 +84,8 @@ PercentVolumeToSoftwareVolume(unsigned volume) ...@@ -87,8 +84,8 @@ PercentVolumeToSoftwareVolume(unsigned volume)
return 0; return 0;
} }
bool void
SoftwareMixer::SetVolume(unsigned new_volume, gcc_unused Error &error) SoftwareMixer::SetVolume(unsigned new_volume)
{ {
assert(new_volume <= 100); assert(new_volume <= 100);
...@@ -96,7 +93,6 @@ SoftwareMixer::SetVolume(unsigned new_volume, gcc_unused Error &error) ...@@ -96,7 +93,6 @@ SoftwareMixer::SetVolume(unsigned new_volume, gcc_unused Error &error)
if (filter != nullptr) if (filter != nullptr)
volume_filter_set(filter, PercentVolumeToSoftwareVolume(new_volume)); volume_filter_set(filter, PercentVolumeToSoftwareVolume(new_volume));
return true;
} }
const MixerPlugin software_mixer_plugin = { const MixerPlugin software_mixer_plugin = {
......
...@@ -21,11 +21,11 @@ ...@@ -21,11 +21,11 @@
#include "mixer/MixerInternal.hxx" #include "mixer/MixerInternal.hxx"
#include "output/OutputAPI.hxx" #include "output/OutputAPI.hxx"
#include "output/plugins/WinmmOutputPlugin.hxx" #include "output/plugins/WinmmOutputPlugin.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include <mmsystem.h> #include <mmsystem.h>
#include <stdexcept>
#include <assert.h> #include <assert.h>
#include <math.h> #include <math.h>
#include <windows.h> #include <windows.h>
...@@ -40,19 +40,16 @@ public: ...@@ -40,19 +40,16 @@ public:
} }
/* virtual methods from class Mixer */ /* virtual methods from class Mixer */
virtual bool Open(gcc_unused Error &error) override { void Open() override {
return true;
} }
virtual void Close() override { void Close() override {
} }
virtual int GetVolume(Error &error) override; int GetVolume() override;
virtual bool SetVolume(unsigned volume, Error &error) override; void SetVolume(unsigned volume) override;
}; };
static constexpr Domain winmm_mixer_domain("winmm_mixer");
static inline int static inline int
winmm_volume_decode(DWORD volume) winmm_volume_decode(DWORD volume)
{ {
...@@ -69,40 +66,33 @@ winmm_volume_encode(int volume) ...@@ -69,40 +66,33 @@ winmm_volume_encode(int volume)
static Mixer * static Mixer *
winmm_mixer_init(gcc_unused EventLoop &event_loop, AudioOutput &ao, winmm_mixer_init(gcc_unused EventLoop &event_loop, AudioOutput &ao,
MixerListener &listener, MixerListener &listener,
gcc_unused const ConfigBlock &block, gcc_unused const ConfigBlock &block)
gcc_unused Error &error)
{ {
return new WinmmMixer((WinmmOutput &)ao, listener); return new WinmmMixer((WinmmOutput &)ao, listener);
} }
int int
WinmmMixer::GetVolume(Error &error) WinmmMixer::GetVolume()
{ {
DWORD volume; DWORD volume;
HWAVEOUT handle = winmm_output_get_handle(output); HWAVEOUT handle = winmm_output_get_handle(output);
MMRESULT result = waveOutGetVolume(handle, &volume); MMRESULT result = waveOutGetVolume(handle, &volume);
if (result != MMSYSERR_NOERROR) { if (result != MMSYSERR_NOERROR)
error.Set(winmm_mixer_domain, "Failed to get winmm volume"); throw std::runtime_error("Failed to get winmm volume");
return -1;
}
return winmm_volume_decode(volume); return winmm_volume_decode(volume);
} }
bool void
WinmmMixer::SetVolume(unsigned volume, Error &error) WinmmMixer::SetVolume(unsigned volume)
{ {
DWORD value = winmm_volume_encode(volume); DWORD value = winmm_volume_encode(volume);
HWAVEOUT handle = winmm_output_get_handle(output); HWAVEOUT handle = winmm_output_get_handle(output);
MMRESULT result = waveOutSetVolume(handle, value); MMRESULT result = waveOutSetVolume(handle, value);
if (result != MMSYSERR_NOERROR) { if (result != MMSYSERR_NOERROR)
error.Set(winmm_mixer_domain, "Failed to set winmm volume"); throw std::runtime_error("Failed to set winmm volume");
return false;
}
return true;
} }
const MixerPlugin winmm_mixer_plugin = { const MixerPlugin winmm_mixer_plugin = {
......
...@@ -115,8 +115,7 @@ audio_output_load_mixer(EventLoop &event_loop, AudioOutput &ao, ...@@ -115,8 +115,7 @@ audio_output_load_mixer(EventLoop &event_loop, AudioOutput &ao,
const ConfigBlock &block, const ConfigBlock &block,
const MixerPlugin *plugin, const MixerPlugin *plugin,
PreparedFilter &filter_chain, PreparedFilter &filter_chain,
MixerListener &listener, MixerListener &listener)
Error &error)
{ {
Mixer *mixer; Mixer *mixer;
...@@ -127,20 +126,19 @@ audio_output_load_mixer(EventLoop &event_loop, AudioOutput &ao, ...@@ -127,20 +126,19 @@ audio_output_load_mixer(EventLoop &event_loop, AudioOutput &ao,
case MixerType::NULL_: case MixerType::NULL_:
return mixer_new(event_loop, null_mixer_plugin, ao, listener, return mixer_new(event_loop, null_mixer_plugin, ao, listener,
block, error); block);
case MixerType::HARDWARE: case MixerType::HARDWARE:
if (plugin == nullptr) if (plugin == nullptr)
return nullptr; return nullptr;
return mixer_new(event_loop, *plugin, ao, listener, return mixer_new(event_loop, *plugin, ao, listener,
block, error); block);
case MixerType::SOFTWARE: case MixerType::SOFTWARE:
mixer = mixer_new(event_loop, software_mixer_plugin, ao, mixer = mixer_new(event_loop, software_mixer_plugin, ao,
listener, listener,
ConfigBlock(), ConfigBlock());
IgnoreError());
assert(mixer != nullptr); assert(mixer != nullptr);
filter_chain_append(filter_chain, "software_mixer", filter_chain_append(filter_chain, "software_mixer",
...@@ -246,16 +244,16 @@ audio_output_setup(EventLoop &event_loop, AudioOutput &ao, ...@@ -246,16 +244,16 @@ audio_output_setup(EventLoop &event_loop, AudioOutput &ao,
/* set up the mixer */ /* set up the mixer */
Error mixer_error; try {
ao.mixer = audio_output_load_mixer(event_loop, ao, block, ao.mixer = audio_output_load_mixer(event_loop, ao, block,
ao.plugin.mixer_plugin, ao.plugin.mixer_plugin,
*ao.prepared_filter, *ao.prepared_filter,
mixer_listener, mixer_listener);
mixer_error); } catch (const std::runtime_error &e) {
if (ao.mixer == nullptr && mixer_error.IsDefined()) FormatError(e,
FormatError(mixer_error,
"Failed to initialize hardware mixer for '%s'", "Failed to initialize hardware mixer for '%s'",
ao.name); ao.name);
}
/* use the hardware mixer for replay gain? */ /* use the hardware mixer for replay gain? */
......
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#include "util/Error.hxx" #include "util/Error.hxx"
#include "Log.hxx" #include "Log.hxx"
#include <stdexcept>
#include <assert.h> #include <assert.h>
/** after a failure, wait this number of seconds before /** after a failure, wait this number of seconds before
...@@ -145,10 +147,11 @@ AudioOutput::Open(const AudioFormat audio_format, const MusicPipe &mp) ...@@ -145,10 +147,11 @@ AudioOutput::Open(const AudioFormat audio_format, const MusicPipe &mp)
const bool open2 = open; const bool open2 = open;
if (open2 && mixer != nullptr) { if (open2 && mixer != nullptr) {
Error error; try {
if (!mixer_open(mixer, error)) mixer_open(mixer);
FormatWarning(output_domain, } catch (const std::runtime_error &e) {
"Failed to open mixer for '%s'", name); FormatError(e, "Failed to open mixer for '%s'", name);
}
} }
return open2; return open2;
......
...@@ -37,6 +37,8 @@ ...@@ -37,6 +37,8 @@
#include <pulse/subscribe.h> #include <pulse/subscribe.h>
#include <pulse/version.h> #include <pulse/version.h>
#include <stdexcept>
#include <assert.h> #include <assert.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
...@@ -74,7 +76,7 @@ public: ...@@ -74,7 +76,7 @@ public:
mixer = nullptr; mixer = nullptr;
} }
bool SetVolume(const pa_cvolume &volume, Error &error); void SetVolume(const pa_cvolume &volume);
struct pa_threaded_mainloop *GetMainloop() { struct pa_threaded_mainloop *GetMainloop() {
return mainloop; return mainloop;
...@@ -217,34 +219,27 @@ pulse_output_clear_mixer(PulseOutput &po, PulseMixer &pm) ...@@ -217,34 +219,27 @@ pulse_output_clear_mixer(PulseOutput &po, PulseMixer &pm)
po.ClearMixer(pm); po.ClearMixer(pm);
} }
inline bool inline void
PulseOutput::SetVolume(const pa_cvolume &volume, Error &error) PulseOutput::SetVolume(const pa_cvolume &volume)
{ {
if (context == nullptr || stream == nullptr || if (context == nullptr || stream == nullptr ||
pa_stream_get_state(stream) != PA_STREAM_READY) { pa_stream_get_state(stream) != PA_STREAM_READY)
error.Set(pulse_domain, "disconnected"); throw std::runtime_error("disconnected");
return false;
}
pa_operation *o = pa_operation *o =
pa_context_set_sink_input_volume(context, pa_context_set_sink_input_volume(context,
pa_stream_get_index(stream), pa_stream_get_index(stream),
&volume, nullptr, nullptr); &volume, nullptr, nullptr);
if (o == nullptr) { if (o == nullptr)
SetPulseError(error, context, throw std::runtime_error("failed to set PulseAudio volume");
"failed to set PulseAudio volume");
return false;
}
pa_operation_unref(o); pa_operation_unref(o);
return true;
} }
bool void
pulse_output_set_volume(PulseOutput &po, const pa_cvolume *volume, pulse_output_set_volume(PulseOutput &po, const pa_cvolume *volume)
Error &error)
{ {
return po.SetVolume(*volume, error); return po.SetVolume(*volume);
} }
/** /**
......
...@@ -36,8 +36,7 @@ pulse_output_set_mixer(PulseOutput &po, PulseMixer &pm); ...@@ -36,8 +36,7 @@ pulse_output_set_mixer(PulseOutput &po, PulseMixer &pm);
void void
pulse_output_clear_mixer(PulseOutput &po, PulseMixer &pm); pulse_output_clear_mixer(PulseOutput &po, PulseMixer &pm);
bool void
pulse_output_set_volume(PulseOutput &po, pulse_output_set_volume(PulseOutput &po, const pa_cvolume *volume);
const pa_cvolume *volume, Error &error);
#endif #endif
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "Log.hxx" #include "Log.hxx"
#include <string> #include <string>
#include <stdexcept>
/* libroar/services.h declares roar_service_stream::new - work around /* libroar/services.h declares roar_service_stream::new - work around
this C++ problem */ this C++ problem */
...@@ -74,7 +75,7 @@ public: ...@@ -74,7 +75,7 @@ public:
void Cancel(); void Cancel();
int GetVolume() const; int GetVolume() const;
bool SetVolume(unsigned volume); void SetVolume(unsigned volume);
}; };
static constexpr Domain roar_output_domain("roar_output"); static constexpr Domain roar_output_domain("roar_output");
...@@ -90,7 +91,7 @@ RoarOutput::GetVolume() const ...@@ -90,7 +91,7 @@ RoarOutput::GetVolume() const
float l, r; float l, r;
int error; int error;
if (roar_vs_volume_get(vss, &l, &r, &error) < 0) if (roar_vs_volume_get(vss, &l, &r, &error) < 0)
return -1; throw std::runtime_error(roar_vs_strerr(error));
return (l + r) * 50; return (l + r) * 50;
} }
...@@ -101,26 +102,26 @@ roar_output_get_volume(RoarOutput &roar) ...@@ -101,26 +102,26 @@ roar_output_get_volume(RoarOutput &roar)
return roar.GetVolume(); return roar.GetVolume();
} }
bool inline void
RoarOutput::SetVolume(unsigned volume) RoarOutput::SetVolume(unsigned volume)
{ {
assert(volume <= 100); assert(volume <= 100);
const ScopeLock protect(mutex); const ScopeLock protect(mutex);
if (vss == nullptr || !alive) if (vss == nullptr || !alive)
return false; throw std::runtime_error("closed");
int error; int error;
float level = volume / 100.0; float level = volume / 100.0;
roar_vs_volume_mono(vss, level, &error); if (roar_vs_volume_mono(vss, level, &error) < 0)
return true; throw std::runtime_error(roar_vs_strerr(error));
} }
bool void
roar_output_set_volume(RoarOutput &roar, unsigned volume) roar_output_set_volume(RoarOutput &roar, unsigned volume)
{ {
return roar.SetVolume(volume); roar.SetVolume(volume);
} }
inline void inline void
......
...@@ -27,7 +27,7 @@ extern const struct AudioOutputPlugin roar_output_plugin; ...@@ -27,7 +27,7 @@ extern const struct AudioOutputPlugin roar_output_plugin;
int int
roar_output_get_volume(RoarOutput &roar); roar_output_get_volume(RoarOutput &roar);
bool void
roar_output_set_volume(RoarOutput &roar, unsigned volume); roar_output_set_volume(RoarOutput &roar, unsigned volume);
#endif #endif
...@@ -41,7 +41,7 @@ filter_plugin_by_name(gcc_unused const char *name) ...@@ -41,7 +41,7 @@ filter_plugin_by_name(gcc_unused const char *name)
} }
int main(int argc, gcc_unused char **argv) int main(int argc, gcc_unused char **argv)
{ try {
int volume; int volume;
if (argc != 2) { if (argc != 2) {
...@@ -51,36 +51,27 @@ int main(int argc, gcc_unused char **argv) ...@@ -51,36 +51,27 @@ int main(int argc, gcc_unused char **argv)
EventLoop event_loop; EventLoop event_loop;
Error error;
Mixer *mixer = mixer_new(event_loop, alsa_mixer_plugin, Mixer *mixer = mixer_new(event_loop, alsa_mixer_plugin,
*(AudioOutput *)nullptr, *(AudioOutput *)nullptr,
*(MixerListener *)nullptr, *(MixerListener *)nullptr,
ConfigBlock(), error); ConfigBlock());
if (mixer == NULL) {
LogError(error, "mixer_new() failed");
return EXIT_FAILURE;
}
if (!mixer_open(mixer, error)) { mixer_open(mixer);
mixer_free(mixer);
LogError(error, "failed to open the mixer");
return EXIT_FAILURE;
}
volume = mixer_get_volume(mixer, error); volume = mixer_get_volume(mixer);
mixer_close(mixer); mixer_close(mixer);
mixer_free(mixer); mixer_free(mixer);
assert(volume >= -1 && volume <= 100); assert(volume >= -1 && volume <= 100);
if (volume < 0) { if (volume < 0) {
if (error.IsDefined()) { fprintf(stderr, "failed to read volume\n");
LogError(error, "failed to read volume");
} else
fprintf(stderr, "failed to read volume\n");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
printf("%d\n", volume); printf("%d\n", volume);
return 0; return 0;
} catch (const std::exception &e) {
LogError(e);
return EXIT_FAILURE;
} }
...@@ -41,11 +41,10 @@ ...@@ -41,11 +41,10 @@
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
bool void
mixer_set_volume(gcc_unused Mixer *mixer, mixer_set_volume(gcc_unused Mixer *mixer,
gcc_unused unsigned volume, gcc_unused Error &error) gcc_unused unsigned volume)
{ {
return true;
} }
static PreparedFilter * static PreparedFilter *
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment