Commit b6df4680 authored by Max Kellermann's avatar Max Kellermann

MixerPlugin: convert function pointers to Mixer virtual methods

parent e04090b4
...@@ -46,7 +46,7 @@ mixer_free(Mixer *mixer) ...@@ -46,7 +46,7 @@ mixer_free(Mixer *mixer)
this point (see mixer_auto_close()) */ this point (see mixer_auto_close()) */
mixer_close(mixer); mixer_close(mixer);
mixer->plugin.finish(mixer); delete mixer;
} }
bool bool
...@@ -58,12 +58,7 @@ mixer_open(Mixer *mixer, Error &error) ...@@ -58,12 +58,7 @@ mixer_open(Mixer *mixer, Error &error)
const ScopeLock protect(mixer->mutex); const ScopeLock protect(mixer->mutex);
if (mixer->open) success = mixer->open || (mixer->open = mixer->Open(error));
success = true;
else if (mixer->plugin.open == nullptr)
success = mixer->open = true;
else
success = mixer->open = mixer->plugin.open(mixer, error);
mixer->failed = !success; mixer->failed = !success;
...@@ -76,9 +71,7 @@ mixer_close_internal(Mixer *mixer) ...@@ -76,9 +71,7 @@ mixer_close_internal(Mixer *mixer)
assert(mixer != nullptr); assert(mixer != nullptr);
assert(mixer->open); assert(mixer->open);
if (mixer->plugin.close != nullptr) mixer->Close();
mixer->plugin.close(mixer);
mixer->open = false; mixer->open = false;
} }
...@@ -128,7 +121,7 @@ mixer_get_volume(Mixer *mixer, Error &error) ...@@ -128,7 +121,7 @@ mixer_get_volume(Mixer *mixer, Error &error)
const ScopeLock protect(mixer->mutex); const ScopeLock protect(mixer->mutex);
if (mixer->open) { if (mixer->open) {
volume = mixer->plugin.get_volume(mixer, error); volume = mixer->GetVolume(error);
if (volume < 0 && error.IsDefined()) if (volume < 0 && error.IsDefined())
mixer_failed(mixer); mixer_failed(mixer);
} else } else
...@@ -149,6 +142,5 @@ mixer_set_volume(Mixer *mixer, unsigned volume, Error &error) ...@@ -149,6 +142,5 @@ mixer_set_volume(Mixer *mixer, unsigned volume, Error &error)
const ScopeLock protect(mixer->mutex); const ScopeLock protect(mixer->mutex);
return mixer->open && return mixer->open && mixer->SetVolume(volume, error);
mixer->plugin.set_volume(mixer, volume, error);
} }
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "MixerPlugin.hxx" #include "MixerPlugin.hxx"
#include "MixerList.hxx" #include "MixerList.hxx"
#include "thread/Mutex.hxx" #include "thread/Mutex.hxx"
#include "Compiler.h"
class Mixer { class Mixer {
public: public:
...@@ -53,9 +54,40 @@ public: ...@@ -53,9 +54,40 @@ public:
Mixer(const Mixer &) = delete; Mixer(const Mixer &) = delete;
virtual ~Mixer() {}
bool IsPlugin(const MixerPlugin &other) const { bool IsPlugin(const MixerPlugin &other) const {
return &plugin == &other; return &plugin == &other;
} }
/**
* Open mixer device
*
* @return true on success, false on error
*/
virtual bool Open(Error &error) = 0;
/**
* Close mixer device
*/
virtual void Close() = 0;
/**
* Reads the current volume.
*
* @return the current volume (0..100 including) or -1 if
* unavailable or on error (error set, mixer will be closed)
*/
gcc_pure
virtual int GetVolume(Error &error) = 0;
/**
* Sets the volume.
*
* @param volume the new volume (0..100 including) @return
* true on success, false on error
*/
virtual bool SetVolume(unsigned volume, Error &error) = 0;
}; };
#endif #endif
...@@ -47,46 +47,6 @@ struct MixerPlugin { ...@@ -47,46 +47,6 @@ struct MixerPlugin {
Error &error); Error &error);
/** /**
* Finish and free mixer data
*/
void (*finish)(Mixer *data);
/**
* Open mixer device
*
* @param error_r location to store the error occurring, or
* nullptr to ignore errors
* @return true on success, false on error
*/
bool (*open)(Mixer *data, Error &error);
/**
* Close mixer device
*/
void (*close)(Mixer *data);
/**
* Reads the current volume.
*
* @param error_r location to store the error occurring, or
* nullptr to ignore errors
* @return the current volume (0..100 including) or -1 if
* unavailable or on error (error set, mixer will be closed)
*/
int (*get_volume)(Mixer *mixer, Error &error);
/**
* Sets the volume.
*
* @param error_r location to store the error occurring, or
* nullptr to ignore errors
* @param volume the new volume (0..100 including)
* @return true on success, false on error
*/
bool (*set_volume)(Mixer *mixer, unsigned volume,
Error &error);
/**
* If true, then the mixer is automatically opened, even if * If true, then the mixer is automatically opened, even if
* its audio output is not open. If false, then the mixer is * its audio output is not open. If false, then the mixer is
* disabled as long as its audio output is closed. * disabled as long as its audio output is closed.
......
...@@ -79,13 +79,16 @@ public: ...@@ -79,13 +79,16 @@ public:
AlsaMixer(EventLoop &_event_loop) AlsaMixer(EventLoop &_event_loop)
:Mixer(alsa_mixer_plugin), event_loop(_event_loop) {} :Mixer(alsa_mixer_plugin), event_loop(_event_loop) {}
virtual ~AlsaMixer();
void Configure(const config_param &param); void Configure(const config_param &param);
bool Setup(Error &error); bool Setup(Error &error);
bool Open(Error &error);
void Close();
int GetVolume(Error &error); /* virtual methods from class Mixer */
bool SetVolume(unsigned volume, Error &error); virtual bool Open(Error &error) override;
virtual void Close() override;
virtual int GetVolume(Error &error) override;
virtual bool SetVolume(unsigned volume, Error &error) override;
}; };
static constexpr Domain alsa_mixer_domain("alsa_mixer"); static constexpr Domain alsa_mixer_domain("alsa_mixer");
...@@ -174,13 +177,8 @@ alsa_mixer_init(EventLoop &event_loop, gcc_unused void *ao, ...@@ -174,13 +177,8 @@ alsa_mixer_init(EventLoop &event_loop, gcc_unused void *ao,
return am; return am;
} }
static void AlsaMixer::~AlsaMixer()
alsa_mixer_finish(Mixer *data)
{ {
AlsaMixer *am = (AlsaMixer *)data;
delete am;
/* free libasound's config cache */ /* free libasound's config cache */
snd_config_update_free_global(); snd_config_update_free_global();
} }
...@@ -267,14 +265,6 @@ AlsaMixer::Open(Error &error) ...@@ -267,14 +265,6 @@ AlsaMixer::Open(Error &error)
return true; return true;
} }
static bool
alsa_mixer_open(Mixer *data, Error &error)
{
AlsaMixer *am = (AlsaMixer *)data;
return am->Open(error);
}
inline void inline void
AlsaMixer::Close() AlsaMixer::Close()
{ {
...@@ -286,13 +276,6 @@ AlsaMixer::Close() ...@@ -286,13 +276,6 @@ AlsaMixer::Close()
snd_mixer_close(handle); snd_mixer_close(handle);
} }
static void
alsa_mixer_close(Mixer *data)
{
AlsaMixer *am = (AlsaMixer *)data;
am->Close();
}
inline int inline int
AlsaMixer::GetVolume(Error &error) AlsaMixer::GetVolume(Error &error)
{ {
...@@ -332,13 +315,6 @@ AlsaMixer::GetVolume(Error &error) ...@@ -332,13 +315,6 @@ AlsaMixer::GetVolume(Error &error)
return ret; return ret;
} }
static int
alsa_mixer_get_volume(Mixer *mixer, Error &error)
{
AlsaMixer *am = (AlsaMixer *)mixer;
return am->GetVolume(error);
}
inline bool inline bool
AlsaMixer::SetVolume(unsigned volume, Error &error) AlsaMixer::SetVolume(unsigned volume, Error &error)
{ {
...@@ -367,19 +343,7 @@ AlsaMixer::SetVolume(unsigned volume, Error &error) ...@@ -367,19 +343,7 @@ AlsaMixer::SetVolume(unsigned volume, Error &error)
return true; return true;
} }
static bool
alsa_mixer_set_volume(Mixer *mixer, unsigned volume, Error &error)
{
AlsaMixer *am = (AlsaMixer *)mixer;
return am->SetVolume(volume, error);
}
const MixerPlugin alsa_mixer_plugin = { const MixerPlugin alsa_mixer_plugin = {
alsa_mixer_init, alsa_mixer_init,
alsa_mixer_finish,
alsa_mixer_open,
alsa_mixer_close,
alsa_mixer_get_volume,
alsa_mixer_set_volume,
true, true,
}; };
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
#define VOLUME_MIXER_OSS_DEFAULT "/dev/mixer" #define VOLUME_MIXER_OSS_DEFAULT "/dev/mixer"
class OssMixer : public Mixer { class OssMixer final : public Mixer {
const char *device; const char *device;
const char *control; const char *control;
...@@ -52,11 +52,12 @@ public: ...@@ -52,11 +52,12 @@ public:
OssMixer():Mixer(oss_mixer_plugin) {} OssMixer():Mixer(oss_mixer_plugin) {}
bool Configure(const config_param &param, Error &error); bool Configure(const config_param &param, Error &error);
bool Open(Error &error);
void Close();
int GetVolume(Error &error); /* virtual methods from class Mixer */
bool SetVolume(unsigned volume, Error &error); virtual bool Open(Error &error) override;
virtual void Close() override;
virtual int GetVolume(Error &error) override;
virtual bool SetVolume(unsigned volume, Error &error) override;
}; };
static constexpr Domain oss_mixer_domain("oss_mixer"); static constexpr Domain oss_mixer_domain("oss_mixer");
...@@ -110,14 +111,6 @@ oss_mixer_init(gcc_unused EventLoop &event_loop, gcc_unused void *ao, ...@@ -110,14 +111,6 @@ oss_mixer_init(gcc_unused EventLoop &event_loop, gcc_unused void *ao,
return om; return om;
} }
static void
oss_mixer_finish(Mixer *data)
{
OssMixer *om = (OssMixer *) data;
delete om;
}
void void
OssMixer::Close() OssMixer::Close()
{ {
...@@ -126,14 +119,7 @@ OssMixer::Close() ...@@ -126,14 +119,7 @@ OssMixer::Close()
close(device_fd); close(device_fd);
} }
static void bool
oss_mixer_close(Mixer *data)
{
OssMixer *om = (OssMixer *) data;
om->Close();
}
inline bool
OssMixer::Open(Error &error) OssMixer::Open(Error &error)
{ {
device_fd = open_cloexec(device, O_RDONLY, 0); device_fd = open_cloexec(device, O_RDONLY, 0);
...@@ -163,15 +149,7 @@ OssMixer::Open(Error &error) ...@@ -163,15 +149,7 @@ OssMixer::Open(Error &error)
return true; return true;
} }
static bool int
oss_mixer_open(Mixer *data, Error &error)
{
OssMixer *om = (OssMixer *) data;
return om->Open(error);
}
inline int
OssMixer::GetVolume(Error &error) OssMixer::GetVolume(Error &error)
{ {
int left, right, level; int left, right, level;
...@@ -197,14 +175,7 @@ OssMixer::GetVolume(Error &error) ...@@ -197,14 +175,7 @@ OssMixer::GetVolume(Error &error)
return left; return left;
} }
static int bool
oss_mixer_get_volume(Mixer *mixer, Error &error)
{
OssMixer *om = (OssMixer *)mixer;
return om->GetVolume(error);
}
inline bool
OssMixer::SetVolume(unsigned volume, Error &error) OssMixer::SetVolume(unsigned volume, Error &error)
{ {
int level; int level;
...@@ -224,19 +195,7 @@ OssMixer::SetVolume(unsigned volume, Error &error) ...@@ -224,19 +195,7 @@ OssMixer::SetVolume(unsigned volume, Error &error)
return true; return true;
} }
static bool
oss_mixer_set_volume(Mixer *mixer, unsigned volume, Error &error)
{
OssMixer *om = (OssMixer *)mixer;
return om->SetVolume(volume, error);
}
const MixerPlugin oss_mixer_plugin = { const MixerPlugin oss_mixer_plugin = {
oss_mixer_init, oss_mixer_init,
oss_mixer_finish,
oss_mixer_open,
oss_mixer_close,
oss_mixer_get_volume,
oss_mixer_set_volume,
true, true,
}; };
...@@ -34,74 +34,95 @@ ...@@ -34,74 +34,95 @@
#include <assert.h> #include <assert.h>
struct PulseMixer final : public Mixer { class PulseMixer final : public Mixer {
PulseOutput *output; PulseOutput *output;
bool online; bool online;
struct pa_cvolume volume; struct pa_cvolume volume;
public:
PulseMixer(PulseOutput *_output) PulseMixer(PulseOutput *_output)
:Mixer(pulse_mixer_plugin), :Mixer(pulse_mixer_plugin),
output(_output), online(false) output(_output), online(false)
{ {
} }
virtual ~PulseMixer();
void Offline();
void VolumeCallback(const pa_sink_input_info *i, int eol);
void Update(pa_context *context, pa_stream *stream);
/* virtual methods from class Mixer */
virtual bool Open(gcc_unused Error &error) override {
return true;
}
virtual void Close() override {
}
virtual int GetVolume(Error &error) override;
virtual bool SetVolume(unsigned volume, Error &error) override;
}; };
static constexpr Domain pulse_mixer_domain("pulse_mixer"); static constexpr Domain pulse_mixer_domain("pulse_mixer");
static void void
pulse_mixer_offline(PulseMixer *pm) PulseMixer::Offline()
{ {
if (!pm->online) if (!online)
return; return;
pm->online = false; online = false;
GlobalEvents::Emit(GlobalEvents::MIXER); GlobalEvents::Emit(GlobalEvents::MIXER);
} }
/** inline void
* Callback invoked by pulse_mixer_update(). Receives the new mixer PulseMixer::VolumeCallback(const pa_sink_input_info *i, int eol)
* value.
*/
static void
pulse_mixer_volume_cb(gcc_unused pa_context *context, const pa_sink_input_info *i,
int eol, void *userdata)
{ {
PulseMixer *pm = (PulseMixer *)userdata;
if (eol) if (eol)
return; return;
if (i == nullptr) { if (i == nullptr) {
pulse_mixer_offline(pm); Offline();
return; return;
} }
pm->online = true; online = true;
pm->volume = i->volume; volume = i->volume;
GlobalEvents::Emit(GlobalEvents::MIXER); GlobalEvents::Emit(GlobalEvents::MIXER);
} }
/**
* Callback invoked by pulse_mixer_update(). Receives the new mixer
* value.
*/
static void static void
pulse_mixer_update(PulseMixer *pm, pulse_mixer_volume_cb(gcc_unused pa_context *context, const pa_sink_input_info *i,
struct pa_context *context, struct pa_stream *stream) int eol, void *userdata)
{ {
pa_operation *o; PulseMixer *pm = (PulseMixer *)userdata;
pm->VolumeCallback(i, eol);
}
inline void
PulseMixer::Update(pa_context *context, pa_stream *stream)
{
assert(context != nullptr); assert(context != nullptr);
assert(stream != nullptr); assert(stream != nullptr);
assert(pa_stream_get_state(stream) == PA_STREAM_READY); assert(pa_stream_get_state(stream) == PA_STREAM_READY);
o = pa_context_get_sink_input_info(context, pa_operation *o =
pa_stream_get_index(stream), pa_context_get_sink_input_info(context,
pulse_mixer_volume_cb, pm); pa_stream_get_index(stream),
pulse_mixer_volume_cb, this);
if (o == nullptr) { if (o == nullptr) {
FormatError(pulse_mixer_domain, FormatError(pulse_mixer_domain,
"pa_context_get_sink_input_info() failed: %s", "pa_context_get_sink_input_info() failed: %s",
pa_strerror(pa_context_errno(context))); pa_strerror(pa_context_errno(context)));
pulse_mixer_offline(pm); Offline();
return; return;
} }
...@@ -132,14 +153,14 @@ pulse_mixer_on_connect(gcc_unused PulseMixer *pm, ...@@ -132,14 +153,14 @@ pulse_mixer_on_connect(gcc_unused PulseMixer *pm,
void void
pulse_mixer_on_disconnect(PulseMixer *pm) pulse_mixer_on_disconnect(PulseMixer *pm)
{ {
pulse_mixer_offline(pm); pm->Offline();
} }
void void
pulse_mixer_on_change(PulseMixer *pm, pulse_mixer_on_change(PulseMixer *pm,
struct pa_context *context, struct pa_stream *stream) struct pa_context *context, struct pa_stream *stream)
{ {
pulse_mixer_update(pm, context, stream); pm->Update(context, stream);
} }
static Mixer * static Mixer *
...@@ -162,65 +183,48 @@ pulse_mixer_init(gcc_unused EventLoop &event_loop, void *ao, ...@@ -162,65 +183,48 @@ pulse_mixer_init(gcc_unused EventLoop &event_loop, void *ao,
return pm; return pm;
} }
static void PulseMixer::~PulseMixer()
pulse_mixer_finish(Mixer *data)
{ {
PulseMixer *pm = (PulseMixer *) data; pulse_output_clear_mixer(output, this);
pulse_output_clear_mixer(pm->output, pm);
delete pm;
} }
static int int
pulse_mixer_get_volume(Mixer *mixer, gcc_unused Error &error) PulseMixer::GetVolume(gcc_unused Error &error)
{ {
PulseMixer *pm = (PulseMixer *) mixer; pulse_output_lock(output);
int ret;
pulse_output_lock(pm->output);
ret = pm->online int result = online
? (int)((100*(pa_cvolume_avg(&pm->volume)+1))/PA_VOLUME_NORM) ? (int)((100 * (pa_cvolume_avg(&volume) + 1)) / PA_VOLUME_NORM)
: -1; : -1;
pulse_output_unlock(pm->output); pulse_output_unlock(output);
return ret; return result;
} }
static bool bool
pulse_mixer_set_volume(Mixer *mixer, unsigned volume, Error &error) PulseMixer::SetVolume(unsigned new_volume, Error &error)
{ {
PulseMixer *pm = (PulseMixer *) mixer; pulse_output_lock(output);
struct pa_cvolume cvolume;
bool success;
pulse_output_lock(pm->output);
if (!pm->online) { if (!online) {
pulse_output_unlock(pm->output); pulse_output_unlock(output);
error.Set(pulse_mixer_domain, "disconnected"); error.Set(pulse_mixer_domain, "disconnected");
return false; return false;
} }
pa_cvolume_set(&cvolume, pm->volume.channels, struct pa_cvolume cvolume;
(pa_volume_t)volume * PA_VOLUME_NORM / 100 + 0.5); pa_cvolume_set(&cvolume, volume.channels,
success = pulse_output_set_volume(pm->output, &cvolume, error); (pa_volume_t)new_volume * PA_VOLUME_NORM / 100 + 0.5);
bool success = pulse_output_set_volume(output, &cvolume, error);
if (success) if (success)
pm->volume = cvolume; volume = cvolume;
pulse_output_unlock(pm->output);
pulse_output_unlock(output);
return success; return success;
} }
const MixerPlugin pulse_mixer_plugin = { const MixerPlugin pulse_mixer_plugin = {
pulse_mixer_init, pulse_mixer_init,
pulse_mixer_finish,
nullptr,
nullptr,
pulse_mixer_get_volume,
pulse_mixer_set_volume,
false, false,
}; };
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#ifndef MPD_PULSE_MIXER_PLUGIN_HXX #ifndef MPD_PULSE_MIXER_PLUGIN_HXX
#define MPD_PULSE_MIXER_PLUGIN_HXX #define MPD_PULSE_MIXER_PLUGIN_HXX
struct PulseMixer; class PulseMixer;
struct pa_context; struct pa_context;
struct pa_stream; struct pa_stream;
......
...@@ -24,13 +24,25 @@ ...@@ -24,13 +24,25 @@
#include "output/plugins/RoarOutputPlugin.hxx" #include "output/plugins/RoarOutputPlugin.hxx"
#include "Compiler.h" #include "Compiler.h"
struct RoarMixer final : public Mixer { class RoarMixer final : public Mixer {
/** the base mixer class */ /** the base mixer class */
RoarOutput *self; RoarOutput *self;
public:
RoarMixer(RoarOutput *_output) RoarMixer(RoarOutput *_output)
:Mixer(roar_mixer_plugin), :Mixer(roar_mixer_plugin),
self(_output) {} self(_output) {}
/* virtual methods from class Mixer */
virtual bool Open(gcc_unused Error &error) override {
return true;
}
virtual void Close() override {
}
virtual int GetVolume(Error &error) override;
virtual bool SetVolume(unsigned volume, Error &error) override;
}; };
static Mixer * static Mixer *
...@@ -41,35 +53,19 @@ roar_mixer_init(gcc_unused EventLoop &event_loop, void *ao, ...@@ -41,35 +53,19 @@ roar_mixer_init(gcc_unused EventLoop &event_loop, void *ao,
return new RoarMixer((RoarOutput *)ao); return new RoarMixer((RoarOutput *)ao);
} }
static void int
roar_mixer_finish(Mixer *data) RoarMixer::GetVolume(gcc_unused Error &error)
{
RoarMixer *self = (RoarMixer *) data;
delete self;
}
static int
roar_mixer_get_volume(Mixer *mixer, gcc_unused Error &error)
{ {
RoarMixer *self = (RoarMixer *)mixer; return roar_output_get_volume(self);
return roar_output_get_volume(self->self);
} }
static bool bool
roar_mixer_set_volume(Mixer *mixer, unsigned volume, RoarMixer::SetVolume(unsigned volume, gcc_unused Error &error)
gcc_unused Error &error)
{ {
RoarMixer *self = (RoarMixer *)mixer; return roar_output_set_volume(self, volume);
return roar_output_set_volume(self->self, volume);
} }
const MixerPlugin roar_mixer_plugin = { const MixerPlugin roar_mixer_plugin = {
roar_mixer_init, roar_mixer_init,
roar_mixer_finish,
nullptr,
nullptr,
roar_mixer_get_volume,
roar_mixer_set_volume,
false, false,
}; };
...@@ -38,7 +38,7 @@ CreateVolumeFilter() ...@@ -38,7 +38,7 @@ CreateVolumeFilter()
IgnoreError()); IgnoreError());
} }
struct SoftwareMixer final : public Mixer { class SoftwareMixer final : public Mixer {
Filter *filter; Filter *filter;
/** /**
...@@ -51,6 +51,7 @@ struct SoftwareMixer final : public Mixer { ...@@ -51,6 +51,7 @@ struct SoftwareMixer final : public Mixer {
unsigned volume; unsigned volume;
public:
SoftwareMixer() SoftwareMixer()
:Mixer(software_mixer_plugin), :Mixer(software_mixer_plugin),
filter(CreateVolumeFilter()), filter(CreateVolumeFilter()),
...@@ -60,10 +61,26 @@ struct SoftwareMixer final : public Mixer { ...@@ -60,10 +61,26 @@ struct SoftwareMixer final : public Mixer {
assert(filter != nullptr); assert(filter != nullptr);
} }
~SoftwareMixer() { virtual ~SoftwareMixer() {
if (owns_filter) if (owns_filter)
delete filter; delete filter;
} }
Filter *GetFilter();
/* virtual methods from class Mixer */
virtual bool Open(gcc_unused Error &error) override {
return true;
}
virtual void Close() override {
}
virtual int GetVolume(gcc_unused Error &error) override {
return volume;
}
virtual bool SetVolume(unsigned volume, Error &error) override;
}; };
static Mixer * static Mixer *
...@@ -74,59 +91,40 @@ software_mixer_init(gcc_unused EventLoop &event_loop, gcc_unused void *ao, ...@@ -74,59 +91,40 @@ software_mixer_init(gcc_unused EventLoop &event_loop, gcc_unused void *ao,
return new SoftwareMixer(); return new SoftwareMixer();
} }
static void bool
software_mixer_finish(Mixer *data) SoftwareMixer::SetVolume(unsigned new_volume, gcc_unused Error &error)
{ {
SoftwareMixer *sm = (SoftwareMixer *)data; assert(new_volume <= 100);
delete sm;
}
static int if (new_volume >= 100)
software_mixer_get_volume(Mixer *mixer, gcc_unused Error &error) new_volume = PCM_VOLUME_1;
{ else if (new_volume > 0)
SoftwareMixer *sm = (SoftwareMixer *)mixer; new_volume = pcm_float_to_volume((exp(new_volume / 25.0) - 1) /
(54.5981500331F - 1));
return sm->volume; volume = new_volume;
} volume_filter_set(filter, new_volume);
static bool
software_mixer_set_volume(Mixer *mixer, unsigned volume,
gcc_unused Error &error)
{
SoftwareMixer *sm = (SoftwareMixer *)mixer;
assert(volume <= 100);
sm->volume = volume;
if (volume >= 100)
volume = PCM_VOLUME_1;
else if (volume > 0)
volume = pcm_float_to_volume((exp(volume / 25.0) - 1) /
(54.5981500331F - 1));
volume_filter_set(sm->filter, volume);
return true; return true;
} }
const MixerPlugin software_mixer_plugin = { const MixerPlugin software_mixer_plugin = {
software_mixer_init, software_mixer_init,
software_mixer_finish,
nullptr,
nullptr,
software_mixer_get_volume,
software_mixer_set_volume,
true, true,
}; };
inline Filter *
SoftwareMixer::GetFilter()
{
assert(owns_filter);
owns_filter = false;
return filter;
}
Filter * Filter *
software_mixer_get_filter(Mixer *mixer) software_mixer_get_filter(Mixer *mixer)
{ {
SoftwareMixer *sm = (SoftwareMixer *)mixer; SoftwareMixer *sm = (SoftwareMixer *)mixer;
assert(sm->IsPlugin(software_mixer_plugin)); assert(sm->IsPlugin(software_mixer_plugin));
assert(sm->owns_filter); return sm->GetFilter();
sm->owns_filter = false;
return sm->filter;
} }
...@@ -30,13 +30,25 @@ ...@@ -30,13 +30,25 @@
#include <math.h> #include <math.h>
#include <windows.h> #include <windows.h>
struct WinmmMixer final : public Mixer { class WinmmMixer final : public Mixer {
WinmmOutput *output; WinmmOutput *output;
public:
WinmmMixer(WinmmOutput *_output) WinmmMixer(WinmmOutput *_output)
:Mixer(winmm_mixer_plugin), :Mixer(winmm_mixer_plugin),
output(_output) { output(_output) {
} }
/* virtual methods from class Mixer */
virtual bool Open(gcc_unused Error &error) override {
return true;
}
virtual void Close() override {
}
virtual int GetVolume(Error &error) override;
virtual bool SetVolume(unsigned volume, Error &error) override;
}; };
static constexpr Domain winmm_mixer_domain("winmm_mixer"); static constexpr Domain winmm_mixer_domain("winmm_mixer");
...@@ -64,20 +76,11 @@ winmm_mixer_init(gcc_unused EventLoop &event_loop, void *ao, ...@@ -64,20 +76,11 @@ winmm_mixer_init(gcc_unused EventLoop &event_loop, void *ao,
return new WinmmMixer((WinmmOutput *)ao); return new WinmmMixer((WinmmOutput *)ao);
} }
static void int
winmm_mixer_finish(Mixer *data) WinmmMixer::GetVolume(Error &error)
{
WinmmMixer *wm = (WinmmMixer *)data;
delete wm;
}
static int
winmm_mixer_get_volume(Mixer *mixer, Error &error)
{ {
WinmmMixer *wm = (WinmmMixer *) mixer;
DWORD volume; DWORD volume;
HWAVEOUT handle = winmm_output_get_handle(wm->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) {
...@@ -88,12 +91,11 @@ winmm_mixer_get_volume(Mixer *mixer, Error &error) ...@@ -88,12 +91,11 @@ winmm_mixer_get_volume(Mixer *mixer, Error &error)
return winmm_volume_decode(volume); return winmm_volume_decode(volume);
} }
static bool bool
winmm_mixer_set_volume(Mixer *mixer, unsigned volume, Error &error) WinmmMixer::SetVolume(unsigned volume, Error &error)
{ {
WinmmMixer *wm = (WinmmMixer *) mixer;
DWORD value = winmm_volume_encode(volume); DWORD value = winmm_volume_encode(volume);
HWAVEOUT handle = winmm_output_get_handle(wm->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) {
...@@ -106,10 +108,5 @@ winmm_mixer_set_volume(Mixer *mixer, unsigned volume, Error &error) ...@@ -106,10 +108,5 @@ winmm_mixer_set_volume(Mixer *mixer, unsigned volume, Error &error)
const MixerPlugin winmm_mixer_plugin = { const MixerPlugin winmm_mixer_plugin = {
winmm_mixer_init, winmm_mixer_init,
winmm_mixer_finish,
nullptr,
nullptr,
winmm_mixer_get_volume,
winmm_mixer_set_volume,
false, false,
}; };
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#define MPD_PULSE_OUTPUT_PLUGIN_HXX #define MPD_PULSE_OUTPUT_PLUGIN_HXX
struct PulseOutput; struct PulseOutput;
struct PulseMixer; class PulseMixer;
struct pa_cvolume; struct pa_cvolume;
class Error; class Error;
......
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