MixerPlugin: convert function pointers to Mixer virtual methods
This commit is contained in:
@@ -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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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 @@
|
|||||||
#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:
|
|||||||
|
|
||||||
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
|
||||||
|
@@ -46,46 +46,6 @@ struct MixerPlugin {
|
|||||||
const config_param ¶m,
|
const config_param ¶m,
|
||||||
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
|
||||||
|
@@ -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 ¶m);
|
void Configure(const config_param ¶m);
|
||||||
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,
|
|||||||
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)
|
|||||||
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()
|
|||||||
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)
|
|||||||
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)
|
|||||||
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 @@
|
|||||||
|
|
||||||
#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:
|
|||||||
OssMixer():Mixer(oss_mixer_plugin) {}
|
OssMixer():Mixer(oss_mixer_plugin) {}
|
||||||
|
|
||||||
bool Configure(const config_param ¶m, Error &error);
|
bool Configure(const config_param ¶m, 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,
|
|||||||
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()
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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,28 +34,63 @@
|
|||||||
|
|
||||||
#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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
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)
|
int eol, void *userdata)
|
||||||
{
|
{
|
||||||
PulseMixer *pm = (PulseMixer *)userdata;
|
PulseMixer *pm = (PulseMixer *)userdata;
|
||||||
|
pm->VolumeCallback(i, eol);
|
||||||
if (eol)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (i == nullptr) {
|
|
||||||
pulse_mixer_offline(pm);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pm->online = true;
|
|
||||||
pm->volume = i->volume;
|
|
||||||
|
|
||||||
GlobalEvents::Emit(GlobalEvents::MIXER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
inline void
|
||||||
pulse_mixer_update(PulseMixer *pm,
|
PulseMixer::Update(pa_context *context, pa_stream *stream)
|
||||||
struct pa_context *context, struct pa_stream *stream)
|
|
||||||
{
|
{
|
||||||
pa_operation *o;
|
|
||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
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);
|
int result = online
|
||||||
|
? (int)((100 * (pa_cvolume_avg(&volume) + 1)) / PA_VOLUME_NORM)
|
||||||
ret = pm->online
|
|
||||||
? (int)((100*(pa_cvolume_avg(&pm->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 (!online) {
|
||||||
|
pulse_output_unlock(output);
|
||||||
if (!pm->online) {
|
|
||||||
pulse_output_unlock(pm->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 @@
|
|||||||
#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 @@
|
|||||||
#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,
|
|||||||
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;
|
return roar_output_get_volume(self);
|
||||||
|
|
||||||
delete self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
bool
|
||||||
roar_mixer_get_volume(Mixer *mixer, gcc_unused Error &error)
|
RoarMixer::SetVolume(unsigned volume, gcc_unused Error &error)
|
||||||
{
|
{
|
||||||
RoarMixer *self = (RoarMixer *)mixer;
|
return roar_output_set_volume(self, volume);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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()
|
|||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
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,
|
|||||||
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;
|
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
|
volume = new_volume;
|
||||||
software_mixer_get_volume(Mixer *mixer, gcc_unused Error &error)
|
volume_filter_set(filter, new_volume);
|
||||||
{
|
|
||||||
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);
|
|
||||||
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 @@
|
|||||||
#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,
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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 @@
|
|||||||
#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;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user