Mixer: add class MixerListener
Use a listener interface instead of GlobalEvents.
This commit is contained in:
34
src/mixer/Listener.hxx
Normal file
34
src/mixer/Listener.hxx
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MPD_MIXER_LISTENER_HXX
|
||||
#define MPD_MIXER_LISTENER_HXX
|
||||
|
||||
class Mixer;
|
||||
|
||||
/**
|
||||
* An interface that listens on events from mixer plugins. The
|
||||
* methods must be thread-safe and non-blocking.
|
||||
*/
|
||||
class MixerListener {
|
||||
public:
|
||||
virtual void OnMixerVolumeChanged(Mixer &mixer, int volume) = 0;
|
||||
};
|
||||
|
||||
#endif
|
@@ -27,10 +27,11 @@
|
||||
Mixer *
|
||||
mixer_new(EventLoop &event_loop,
|
||||
const MixerPlugin &plugin, AudioOutput &ao,
|
||||
MixerListener &listener,
|
||||
const config_param ¶m,
|
||||
Error &error)
|
||||
{
|
||||
Mixer *mixer = plugin.init(event_loop, ao, param, error);
|
||||
Mixer *mixer = plugin.init(event_loop, ao, listener, param, error);
|
||||
|
||||
assert(mixer == nullptr || mixer->IsPlugin(plugin));
|
||||
|
||||
|
@@ -30,10 +30,12 @@ class Mixer;
|
||||
class EventLoop;
|
||||
struct AudioOutput;
|
||||
struct MixerPlugin;
|
||||
class MixerListener;
|
||||
struct config_param;
|
||||
|
||||
Mixer *
|
||||
mixer_new(EventLoop &event_loop, const MixerPlugin &plugin, AudioOutput &ao,
|
||||
MixerListener &listener,
|
||||
const config_param ¶m,
|
||||
Error &error);
|
||||
|
||||
|
@@ -25,10 +25,14 @@
|
||||
#include "thread/Mutex.hxx"
|
||||
#include "Compiler.h"
|
||||
|
||||
class MixerListener;
|
||||
|
||||
class Mixer {
|
||||
public:
|
||||
const MixerPlugin &plugin;
|
||||
|
||||
MixerListener &listener;
|
||||
|
||||
/**
|
||||
* This mutex protects all of the mixer struct, including its
|
||||
* implementation, so plugins don't have to deal with that.
|
||||
@@ -47,8 +51,8 @@ public:
|
||||
bool failed;
|
||||
|
||||
public:
|
||||
explicit Mixer(const MixerPlugin &_plugin)
|
||||
:plugin(_plugin),
|
||||
explicit Mixer(const MixerPlugin &_plugin, MixerListener &_listener)
|
||||
:plugin(_plugin), listener(_listener),
|
||||
open(false),
|
||||
failed(false) {}
|
||||
|
||||
|
@@ -30,6 +30,7 @@
|
||||
struct config_param;
|
||||
struct AudioOutput;
|
||||
class Mixer;
|
||||
class MixerListener;
|
||||
class EventLoop;
|
||||
class Error;
|
||||
|
||||
@@ -44,6 +45,7 @@ struct MixerPlugin {
|
||||
* @return a mixer object, or nullptr on error
|
||||
*/
|
||||
Mixer *(*init)(EventLoop &event_loop, AudioOutput &ao,
|
||||
MixerListener &listener,
|
||||
const config_param ¶m,
|
||||
Error &error);
|
||||
|
||||
|
@@ -21,7 +21,6 @@
|
||||
#include "Volume.hxx"
|
||||
#include "output/MultipleOutputs.hxx"
|
||||
#include "Idle.hxx"
|
||||
#include "GlobalEvents.hxx"
|
||||
#include "util/StringUtil.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "system/PeriodClock.hxx"
|
||||
@@ -41,22 +40,11 @@ static int last_hardware_volume = -1;
|
||||
/** the age of #last_hardware_volume */
|
||||
static PeriodClock hardware_volume_clock;
|
||||
|
||||
/**
|
||||
* Handler for #GlobalEvents::MIXER.
|
||||
*/
|
||||
static void
|
||||
mixer_event_callback(void)
|
||||
void
|
||||
InvalidateHardwareVolume()
|
||||
{
|
||||
/* flush the hardware volume cache */
|
||||
last_hardware_volume = -1;
|
||||
|
||||
/* notify clients */
|
||||
idle_add(IDLE_MIXER);
|
||||
}
|
||||
|
||||
void volume_init(void)
|
||||
{
|
||||
GlobalEvents::Register(GlobalEvents::MIXER, mixer_event_callback);
|
||||
}
|
||||
|
||||
int
|
||||
|
@@ -26,7 +26,8 @@
|
||||
|
||||
class MultipleOutputs;
|
||||
|
||||
void volume_init(void);
|
||||
void
|
||||
InvalidateHardwareVolume();
|
||||
|
||||
gcc_pure
|
||||
int
|
||||
|
@@ -19,8 +19,8 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "mixer/MixerInternal.hxx"
|
||||
#include "mixer/Listener.hxx"
|
||||
#include "output/OutputAPI.hxx"
|
||||
#include "GlobalEvents.hxx"
|
||||
#include "event/MultiSocketMonitor.hxx"
|
||||
#include "event/DeferredMonitor.hxx"
|
||||
#include "event/Loop.hxx"
|
||||
@@ -76,8 +76,9 @@ class AlsaMixer final : public Mixer {
|
||||
AlsaMixerMonitor *monitor;
|
||||
|
||||
public:
|
||||
AlsaMixer(EventLoop &_event_loop)
|
||||
:Mixer(alsa_mixer_plugin), event_loop(_event_loop) {}
|
||||
AlsaMixer(EventLoop &_event_loop, MixerListener &_listener)
|
||||
:Mixer(alsa_mixer_plugin, _listener),
|
||||
event_loop(_event_loop) {}
|
||||
|
||||
virtual ~AlsaMixer();
|
||||
|
||||
@@ -142,10 +143,15 @@ AlsaMixerMonitor::DispatchSockets()
|
||||
*/
|
||||
|
||||
static int
|
||||
alsa_mixer_elem_callback(gcc_unused snd_mixer_elem_t *elem, unsigned mask)
|
||||
alsa_mixer_elem_callback(snd_mixer_elem_t *elem, unsigned mask)
|
||||
{
|
||||
if (mask & SND_CTL_EVENT_MASK_VALUE)
|
||||
GlobalEvents::Emit(GlobalEvents::MIXER);
|
||||
AlsaMixer &mixer = *(AlsaMixer *)
|
||||
snd_mixer_elem_get_callback_private(elem);
|
||||
|
||||
if (mask & SND_CTL_EVENT_MASK_VALUE) {
|
||||
int volume = mixer.GetVolume(IgnoreError());
|
||||
mixer.listener.OnMixerVolumeChanged(mixer, volume);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -168,10 +174,11 @@ AlsaMixer::Configure(const config_param ¶m)
|
||||
|
||||
static Mixer *
|
||||
alsa_mixer_init(EventLoop &event_loop, gcc_unused AudioOutput &ao,
|
||||
MixerListener &listener,
|
||||
const config_param ¶m,
|
||||
gcc_unused Error &error)
|
||||
{
|
||||
AlsaMixer *am = new AlsaMixer(event_loop);
|
||||
AlsaMixer *am = new AlsaMixer(event_loop, listener);
|
||||
am->Configure(param);
|
||||
|
||||
return am;
|
||||
@@ -236,6 +243,7 @@ AlsaMixer::Setup(Error &error)
|
||||
snd_mixer_selem_get_playback_volume_range(elem, &volume_min,
|
||||
&volume_max);
|
||||
|
||||
snd_mixer_elem_set_callback_private(elem, this);
|
||||
snd_mixer_elem_set_callback(elem, alsa_mixer_elem_callback);
|
||||
|
||||
monitor = new AlsaMixerMonitor(event_loop, handle);
|
||||
|
@@ -49,7 +49,8 @@ class OssMixer final : public Mixer {
|
||||
int volume_control;
|
||||
|
||||
public:
|
||||
OssMixer():Mixer(oss_mixer_plugin) {}
|
||||
OssMixer(MixerListener &_listener)
|
||||
:Mixer(oss_mixer_plugin, _listener) {}
|
||||
|
||||
bool Configure(const config_param ¶m, Error &error);
|
||||
|
||||
@@ -98,10 +99,11 @@ OssMixer::Configure(const config_param ¶m, Error &error)
|
||||
|
||||
static Mixer *
|
||||
oss_mixer_init(gcc_unused EventLoop &event_loop, gcc_unused AudioOutput &ao,
|
||||
MixerListener &listener,
|
||||
const config_param ¶m,
|
||||
Error &error)
|
||||
{
|
||||
OssMixer *om = new OssMixer();
|
||||
OssMixer *om = new OssMixer(listener);
|
||||
|
||||
if (!om->Configure(param, error)) {
|
||||
delete om;
|
||||
|
@@ -20,8 +20,8 @@
|
||||
#include "config.h"
|
||||
#include "PulseMixerPlugin.hxx"
|
||||
#include "mixer/MixerInternal.hxx"
|
||||
#include "mixer/Listener.hxx"
|
||||
#include "output/plugins/PulseOutputPlugin.hxx"
|
||||
#include "GlobalEvents.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "Log.hxx"
|
||||
@@ -41,9 +41,9 @@ class PulseMixer final : public Mixer {
|
||||
struct pa_cvolume volume;
|
||||
|
||||
public:
|
||||
PulseMixer(PulseOutput &_output)
|
||||
:Mixer(pulse_mixer_plugin),
|
||||
output(_output), online(false)
|
||||
PulseMixer(PulseOutput &_output, MixerListener &_listener)
|
||||
:Mixer(pulse_mixer_plugin, _listener),
|
||||
output(_output), online(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ PulseMixer::Offline()
|
||||
|
||||
online = false;
|
||||
|
||||
GlobalEvents::Emit(GlobalEvents::MIXER);
|
||||
listener.OnMixerVolumeChanged(*this, -1);
|
||||
}
|
||||
|
||||
inline void
|
||||
@@ -92,7 +92,7 @@ PulseMixer::VolumeCallback(const pa_sink_input_info *i, int eol)
|
||||
online = true;
|
||||
volume = i->volume;
|
||||
|
||||
GlobalEvents::Emit(GlobalEvents::MIXER);
|
||||
listener.OnMixerVolumeChanged(*this, GetVolume(IgnoreError()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,11 +165,12 @@ pulse_mixer_on_change(PulseMixer &pm,
|
||||
|
||||
static Mixer *
|
||||
pulse_mixer_init(gcc_unused EventLoop &event_loop, AudioOutput &ao,
|
||||
MixerListener &listener,
|
||||
gcc_unused const config_param ¶m,
|
||||
gcc_unused Error &error)
|
||||
{
|
||||
PulseOutput &po = (PulseOutput &)ao;
|
||||
PulseMixer *pm = new PulseMixer(po);
|
||||
PulseMixer *pm = new PulseMixer(po, listener);
|
||||
|
||||
pulse_output_set_mixer(po, *pm);
|
||||
|
||||
|
@@ -29,9 +29,9 @@ class RoarMixer final : public Mixer {
|
||||
RoarOutput &self;
|
||||
|
||||
public:
|
||||
RoarMixer(RoarOutput &_output)
|
||||
:Mixer(roar_mixer_plugin),
|
||||
self(_output) {}
|
||||
RoarMixer(RoarOutput &_output, MixerListener &_listener)
|
||||
:Mixer(roar_mixer_plugin, _listener),
|
||||
self(_output) {}
|
||||
|
||||
/* virtual methods from class Mixer */
|
||||
virtual bool Open(gcc_unused Error &error) override {
|
||||
@@ -47,10 +47,11 @@ public:
|
||||
|
||||
static Mixer *
|
||||
roar_mixer_init(gcc_unused EventLoop &event_loop, AudioOutput &ao,
|
||||
MixerListener &listener,
|
||||
gcc_unused const config_param ¶m,
|
||||
gcc_unused Error &error)
|
||||
{
|
||||
return new RoarMixer((RoarOutput &)ao);
|
||||
return new RoarMixer((RoarOutput &)ao, listener);
|
||||
}
|
||||
|
||||
int
|
||||
|
@@ -52,8 +52,8 @@ class SoftwareMixer final : public Mixer {
|
||||
unsigned volume;
|
||||
|
||||
public:
|
||||
SoftwareMixer()
|
||||
:Mixer(software_mixer_plugin),
|
||||
SoftwareMixer(MixerListener &_listener)
|
||||
:Mixer(software_mixer_plugin, _listener),
|
||||
filter(CreateVolumeFilter()),
|
||||
owns_filter(true),
|
||||
volume(100)
|
||||
@@ -86,10 +86,11 @@ public:
|
||||
static Mixer *
|
||||
software_mixer_init(gcc_unused EventLoop &event_loop,
|
||||
gcc_unused AudioOutput &ao,
|
||||
MixerListener &listener,
|
||||
gcc_unused const config_param ¶m,
|
||||
gcc_unused Error &error)
|
||||
{
|
||||
return new SoftwareMixer();
|
||||
return new SoftwareMixer(listener);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@@ -34,8 +34,8 @@ class WinmmMixer final : public Mixer {
|
||||
WinmmOutput &output;
|
||||
|
||||
public:
|
||||
WinmmMixer(WinmmOutput &_output)
|
||||
:Mixer(winmm_mixer_plugin),
|
||||
WinmmMixer(WinmmOutput &_output, MixerListener &_listener)
|
||||
:Mixer(winmm_mixer_plugin, _listener),
|
||||
output(_output) {
|
||||
}
|
||||
|
||||
@@ -68,10 +68,11 @@ winmm_volume_encode(int volume)
|
||||
|
||||
static Mixer *
|
||||
winmm_mixer_init(gcc_unused EventLoop &event_loop, AudioOutput &ao,
|
||||
MixerListener &listener,
|
||||
gcc_unused const config_param ¶m,
|
||||
gcc_unused Error &error)
|
||||
{
|
||||
return new WinmmMixer((WinmmOutput &)ao);
|
||||
return new WinmmMixer((WinmmOutput &)ao, listener);
|
||||
}
|
||||
|
||||
int
|
||||
|
Reference in New Issue
Block a user