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