Mixer: add class MixerListener

Use a listener interface instead of GlobalEvents.
This commit is contained in:
Max Kellermann 2014-02-05 23:20:33 +01:00
parent f4f8fa7c94
commit 8d6fedf817
24 changed files with 144 additions and 74 deletions

View File

@ -1033,6 +1033,7 @@ MIXER_LIBS = \
$(PULSE_LIBS) $(PULSE_LIBS)
MIXER_API_SRC = \ MIXER_API_SRC = \
src/mixer/Listener.hxx \
src/mixer/MixerPlugin.hxx \ src/mixer/MixerPlugin.hxx \
src/mixer/MixerList.hxx \ src/mixer/MixerList.hxx \
src/mixer/MixerControl.cxx src/mixer/MixerControl.hxx \ src/mixer/MixerControl.cxx src/mixer/MixerControl.hxx \

View File

@ -42,9 +42,6 @@ namespace GlobalEvents {
/** the current song's tag has changed */ /** the current song's tag has changed */
TAG, TAG,
/** a hardware mixer plugin has detected a change */
MIXER,
#ifdef WIN32 #ifdef WIN32
/** shutdown requested */ /** shutdown requested */
SHUTDOWN, SHUTDOWN,

View File

@ -33,7 +33,6 @@
#include "client/ClientList.hxx" #include "client/ClientList.hxx"
#include "command/AllCommands.hxx" #include "command/AllCommands.hxx"
#include "Partition.hxx" #include "Partition.hxx"
#include "mixer/Volume.hxx"
#include "tag/TagConfig.hxx" #include "tag/TagConfig.hxx"
#include "ReplayGainConfig.hxx" #include "ReplayGainConfig.hxx"
#include "Idle.hxx" #include "Idle.hxx"
@ -469,7 +468,6 @@ int mpd_main(int argc, char *argv[])
command_init(); command_init();
initialize_decoder_and_player(); initialize_decoder_and_player();
volume_init();
initAudioConfig(); initAudioConfig();
instance->partition->outputs.Configure(*instance->event_loop, instance->partition->outputs.Configure(*instance->event_loop,
instance->partition->pc); instance->partition->pc);

View File

@ -21,6 +21,8 @@
#include "Partition.hxx" #include "Partition.hxx"
#include "DetachedSong.hxx" #include "DetachedSong.hxx"
#include "output/MultipleOutputs.hxx" #include "output/MultipleOutputs.hxx"
#include "mixer/Volume.hxx"
#include "Idle.hxx"
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
@ -47,3 +49,12 @@ Partition::SyncWithPlayer()
{ {
playlist.SyncWithPlayer(pc); playlist.SyncWithPlayer(pc);
} }
void
Partition::OnMixerVolumeChanged(gcc_unused Mixer &mixer, gcc_unused int volume)
{
InvalidateHardwareVolume();
/* notify clients */
idle_add(IDLE_MIXER);
}

View File

@ -22,6 +22,7 @@
#include "Playlist.hxx" #include "Playlist.hxx"
#include "output/MultipleOutputs.hxx" #include "output/MultipleOutputs.hxx"
#include "mixer/Listener.hxx"
#include "PlayerControl.hxx" #include "PlayerControl.hxx"
struct Instance; struct Instance;
@ -32,7 +33,7 @@ class SongLoader;
* A partition of the Music Player Daemon. It is a separate unit with * A partition of the Music Player Daemon. It is a separate unit with
* a playlist, a player, outputs etc. * a playlist, a player, outputs etc.
*/ */
struct Partition { struct Partition final : private MixerListener {
Instance &instance; Instance &instance;
struct playlist playlist; struct playlist playlist;
@ -46,6 +47,7 @@ struct Partition {
unsigned buffer_chunks, unsigned buffer_chunks,
unsigned buffered_before_play) unsigned buffered_before_play)
:instance(_instance), playlist(max_length), :instance(_instance), playlist(max_length),
outputs(*this),
pc(outputs, buffer_chunks, buffered_before_play) {} pc(outputs, buffer_chunks, buffered_before_play) {}
void ClearQueue() { void ClearQueue() {
@ -188,6 +190,10 @@ struct Partition {
* Synchronize the player with the play queue. * Synchronize the player with the play queue.
*/ */
void SyncWithPlayer(); void SyncWithPlayer();
private:
/* virtual methods from class MixerListener */
virtual void OnMixerVolumeChanged(Mixer &mixer, int volume) override;
}; };
#endif #endif

34
src/mixer/Listener.hxx Normal file
View 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

View File

@ -27,10 +27,11 @@
Mixer * Mixer *
mixer_new(EventLoop &event_loop, mixer_new(EventLoop &event_loop,
const MixerPlugin &plugin, AudioOutput &ao, const MixerPlugin &plugin, AudioOutput &ao,
MixerListener &listener,
const config_param &param, const config_param &param,
Error &error) 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)); assert(mixer == nullptr || mixer->IsPlugin(plugin));

View File

@ -30,10 +30,12 @@ class Mixer;
class EventLoop; class EventLoop;
struct AudioOutput; struct AudioOutput;
struct MixerPlugin; struct MixerPlugin;
class MixerListener;
struct config_param; struct config_param;
Mixer * Mixer *
mixer_new(EventLoop &event_loop, const MixerPlugin &plugin, AudioOutput &ao, mixer_new(EventLoop &event_loop, const MixerPlugin &plugin, AudioOutput &ao,
MixerListener &listener,
const config_param &param, const config_param &param,
Error &error); Error &error);

View File

@ -25,10 +25,14 @@
#include "thread/Mutex.hxx" #include "thread/Mutex.hxx"
#include "Compiler.h" #include "Compiler.h"
class MixerListener;
class Mixer { class Mixer {
public: public:
const MixerPlugin &plugin; const MixerPlugin &plugin;
MixerListener &listener;
/** /**
* This mutex protects all of the mixer struct, including its * This mutex protects all of the mixer struct, including its
* implementation, so plugins don't have to deal with that. * implementation, so plugins don't have to deal with that.
@ -47,8 +51,8 @@ public:
bool failed; bool failed;
public: public:
explicit Mixer(const MixerPlugin &_plugin) explicit Mixer(const MixerPlugin &_plugin, MixerListener &_listener)
:plugin(_plugin), :plugin(_plugin), listener(_listener),
open(false), open(false),
failed(false) {} failed(false) {}

View File

@ -30,6 +30,7 @@
struct config_param; struct config_param;
struct AudioOutput; struct AudioOutput;
class Mixer; class Mixer;
class MixerListener;
class EventLoop; class EventLoop;
class Error; class Error;
@ -44,6 +45,7 @@ struct MixerPlugin {
* @return a mixer object, or nullptr on error * @return a mixer object, or nullptr on error
*/ */
Mixer *(*init)(EventLoop &event_loop, AudioOutput &ao, Mixer *(*init)(EventLoop &event_loop, AudioOutput &ao,
MixerListener &listener,
const config_param &param, const config_param &param,
Error &error); Error &error);

View File

@ -21,7 +21,6 @@
#include "Volume.hxx" #include "Volume.hxx"
#include "output/MultipleOutputs.hxx" #include "output/MultipleOutputs.hxx"
#include "Idle.hxx" #include "Idle.hxx"
#include "GlobalEvents.hxx"
#include "util/StringUtil.hxx" #include "util/StringUtil.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
#include "system/PeriodClock.hxx" #include "system/PeriodClock.hxx"
@ -41,22 +40,11 @@ static int last_hardware_volume = -1;
/** the age of #last_hardware_volume */ /** the age of #last_hardware_volume */
static PeriodClock hardware_volume_clock; static PeriodClock hardware_volume_clock;
/** void
* Handler for #GlobalEvents::MIXER. InvalidateHardwareVolume()
*/
static void
mixer_event_callback(void)
{ {
/* flush the hardware volume cache */ /* flush the hardware volume cache */
last_hardware_volume = -1; last_hardware_volume = -1;
/* notify clients */
idle_add(IDLE_MIXER);
}
void volume_init(void)
{
GlobalEvents::Register(GlobalEvents::MIXER, mixer_event_callback);
} }
int int

View File

@ -26,7 +26,8 @@
class MultipleOutputs; class MultipleOutputs;
void volume_init(void); void
InvalidateHardwareVolume();
gcc_pure gcc_pure
int int

View File

@ -19,8 +19,8 @@
#include "config.h" #include "config.h"
#include "mixer/MixerInternal.hxx" #include "mixer/MixerInternal.hxx"
#include "mixer/Listener.hxx"
#include "output/OutputAPI.hxx" #include "output/OutputAPI.hxx"
#include "GlobalEvents.hxx"
#include "event/MultiSocketMonitor.hxx" #include "event/MultiSocketMonitor.hxx"
#include "event/DeferredMonitor.hxx" #include "event/DeferredMonitor.hxx"
#include "event/Loop.hxx" #include "event/Loop.hxx"
@ -76,8 +76,9 @@ class AlsaMixer final : public Mixer {
AlsaMixerMonitor *monitor; AlsaMixerMonitor *monitor;
public: public:
AlsaMixer(EventLoop &_event_loop) AlsaMixer(EventLoop &_event_loop, MixerListener &_listener)
:Mixer(alsa_mixer_plugin), event_loop(_event_loop) {} :Mixer(alsa_mixer_plugin, _listener),
event_loop(_event_loop) {}
virtual ~AlsaMixer(); virtual ~AlsaMixer();
@ -142,10 +143,15 @@ AlsaMixerMonitor::DispatchSockets()
*/ */
static int 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) AlsaMixer &mixer = *(AlsaMixer *)
GlobalEvents::Emit(GlobalEvents::MIXER); 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; return 0;
} }
@ -168,10 +174,11 @@ AlsaMixer::Configure(const config_param &param)
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,
const config_param &param, const config_param &param,
gcc_unused Error &error) gcc_unused Error &error)
{ {
AlsaMixer *am = new AlsaMixer(event_loop); AlsaMixer *am = new AlsaMixer(event_loop, listener);
am->Configure(param); am->Configure(param);
return am; return am;
@ -236,6 +243,7 @@ AlsaMixer::Setup(Error &error)
snd_mixer_selem_get_playback_volume_range(elem, &volume_min, snd_mixer_selem_get_playback_volume_range(elem, &volume_min,
&volume_max); &volume_max);
snd_mixer_elem_set_callback_private(elem, this);
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);

View File

@ -49,7 +49,8 @@ class OssMixer final : public Mixer {
int volume_control; int volume_control;
public: public:
OssMixer():Mixer(oss_mixer_plugin) {} OssMixer(MixerListener &_listener)
:Mixer(oss_mixer_plugin, _listener) {}
bool Configure(const config_param &param, Error &error); bool Configure(const config_param &param, Error &error);
@ -98,10 +99,11 @@ OssMixer::Configure(const config_param &param, Error &error)
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,
const config_param &param, const config_param &param,
Error &error) Error &error)
{ {
OssMixer *om = new OssMixer(); OssMixer *om = new OssMixer(listener);
if (!om->Configure(param, error)) { if (!om->Configure(param, error)) {
delete om; delete om;

View File

@ -20,8 +20,8 @@
#include "config.h" #include "config.h"
#include "PulseMixerPlugin.hxx" #include "PulseMixerPlugin.hxx"
#include "mixer/MixerInternal.hxx" #include "mixer/MixerInternal.hxx"
#include "mixer/Listener.hxx"
#include "output/plugins/PulseOutputPlugin.hxx" #include "output/plugins/PulseOutputPlugin.hxx"
#include "GlobalEvents.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
#include "Log.hxx" #include "Log.hxx"
@ -41,9 +41,9 @@ class PulseMixer final : public Mixer {
struct pa_cvolume volume; struct pa_cvolume volume;
public: public:
PulseMixer(PulseOutput &_output) PulseMixer(PulseOutput &_output, MixerListener &_listener)
:Mixer(pulse_mixer_plugin), :Mixer(pulse_mixer_plugin, _listener),
output(_output), online(false) output(_output), online(false)
{ {
} }
@ -75,7 +75,7 @@ PulseMixer::Offline()
online = false; online = false;
GlobalEvents::Emit(GlobalEvents::MIXER); listener.OnMixerVolumeChanged(*this, -1);
} }
inline void inline void
@ -92,7 +92,7 @@ PulseMixer::VolumeCallback(const pa_sink_input_info *i, int eol)
online = true; online = true;
volume = i->volume; volume = i->volume;
GlobalEvents::Emit(GlobalEvents::MIXER); listener.OnMixerVolumeChanged(*this, GetVolume(IgnoreError()));
} }
/** /**
@ -165,11 +165,12 @@ 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,
gcc_unused const config_param &param, gcc_unused const config_param &param,
gcc_unused Error &error) gcc_unused Error &error)
{ {
PulseOutput &po = (PulseOutput &)ao; PulseOutput &po = (PulseOutput &)ao;
PulseMixer *pm = new PulseMixer(po); PulseMixer *pm = new PulseMixer(po, listener);
pulse_output_set_mixer(po, *pm); pulse_output_set_mixer(po, *pm);

View File

@ -29,9 +29,9 @@ class RoarMixer final : public Mixer {
RoarOutput &self; RoarOutput &self;
public: public:
RoarMixer(RoarOutput &_output) RoarMixer(RoarOutput &_output, MixerListener &_listener)
:Mixer(roar_mixer_plugin), :Mixer(roar_mixer_plugin, _listener),
self(_output) {} self(_output) {}
/* virtual methods from class Mixer */ /* virtual methods from class Mixer */
virtual bool Open(gcc_unused Error &error) override { virtual bool Open(gcc_unused Error &error) override {
@ -47,10 +47,11 @@ public:
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,
gcc_unused const config_param &param, gcc_unused const config_param &param,
gcc_unused Error &error) gcc_unused Error &error)
{ {
return new RoarMixer((RoarOutput &)ao); return new RoarMixer((RoarOutput &)ao, listener);
} }
int int

View File

@ -52,8 +52,8 @@ class SoftwareMixer final : public Mixer {
unsigned volume; unsigned volume;
public: public:
SoftwareMixer() SoftwareMixer(MixerListener &_listener)
:Mixer(software_mixer_plugin), :Mixer(software_mixer_plugin, _listener),
filter(CreateVolumeFilter()), filter(CreateVolumeFilter()),
owns_filter(true), owns_filter(true),
volume(100) volume(100)
@ -86,10 +86,11 @@ public:
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,
gcc_unused const config_param &param, gcc_unused const config_param &param,
gcc_unused Error &error) gcc_unused Error &error)
{ {
return new SoftwareMixer(); return new SoftwareMixer(listener);
} }
bool bool

View File

@ -34,8 +34,8 @@ class WinmmMixer final : public Mixer {
WinmmOutput &output; WinmmOutput &output;
public: public:
WinmmMixer(WinmmOutput &_output) WinmmMixer(WinmmOutput &_output, MixerListener &_listener)
:Mixer(winmm_mixer_plugin), :Mixer(winmm_mixer_plugin, _listener),
output(_output) { output(_output) {
} }
@ -68,10 +68,11 @@ 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,
gcc_unused const config_param &param, gcc_unused const config_param &param,
gcc_unused Error &error) gcc_unused Error &error)
{ {
return new WinmmMixer((WinmmOutput &)ao); return new WinmmMixer((WinmmOutput &)ao, listener);
} }
int int

View File

@ -116,6 +116,7 @@ audio_output_load_mixer(EventLoop &event_loop, AudioOutput &ao,
const config_param &param, const config_param &param,
const MixerPlugin *plugin, const MixerPlugin *plugin,
Filter &filter_chain, Filter &filter_chain,
MixerListener &listener,
Error &error) Error &error)
{ {
Mixer *mixer; Mixer *mixer;
@ -129,10 +130,12 @@ audio_output_load_mixer(EventLoop &event_loop, AudioOutput &ao,
if (plugin == nullptr) if (plugin == nullptr)
return nullptr; return nullptr;
return mixer_new(event_loop, *plugin, ao, param, error); return mixer_new(event_loop, *plugin, ao, listener,
param, error);
case MIXER_TYPE_SOFTWARE: case MIXER_TYPE_SOFTWARE:
mixer = mixer_new(event_loop, software_mixer_plugin, ao, mixer = mixer_new(event_loop, software_mixer_plugin, ao,
listener,
config_param(), config_param(),
IgnoreError()); IgnoreError());
assert(mixer != nullptr); assert(mixer != nullptr);
@ -212,6 +215,7 @@ AudioOutput::Configure(const config_param &param, Error &error)
static bool static bool
audio_output_setup(EventLoop &event_loop, AudioOutput &ao, audio_output_setup(EventLoop &event_loop, AudioOutput &ao,
MixerListener &mixer_listener,
const config_param &param, const config_param &param,
Error &error) Error &error)
{ {
@ -244,7 +248,9 @@ audio_output_setup(EventLoop &event_loop, AudioOutput &ao,
Error mixer_error; Error mixer_error;
ao.mixer = audio_output_load_mixer(event_loop, ao, param, ao.mixer = audio_output_load_mixer(event_loop, ao, param,
ao.plugin.mixer_plugin, ao.plugin.mixer_plugin,
*ao.filter, mixer_error); *ao.filter,
mixer_listener,
mixer_error);
if (ao.mixer == nullptr && mixer_error.IsDefined()) if (ao.mixer == nullptr && mixer_error.IsDefined())
FormatError(mixer_error, FormatError(mixer_error,
"Failed to initialize hardware mixer for '%s'", "Failed to initialize hardware mixer for '%s'",
@ -279,6 +285,7 @@ audio_output_setup(EventLoop &event_loop, AudioOutput &ao,
AudioOutput * AudioOutput *
audio_output_new(EventLoop &event_loop, const config_param &param, audio_output_new(EventLoop &event_loop, const config_param &param,
MixerListener &mixer_listener,
PlayerControl &pc, PlayerControl &pc,
Error &error) Error &error)
{ {
@ -317,7 +324,8 @@ audio_output_new(EventLoop &event_loop, const config_param &param,
if (ao == nullptr) if (ao == nullptr)
return nullptr; return nullptr;
if (!audio_output_setup(event_loop, *ao, param, error)) { if (!audio_output_setup(event_loop, *ao, mixer_listener,
param, error)) {
ao_plugin_finish(ao); ao_plugin_finish(ao);
return nullptr; return nullptr;
} }

View File

@ -33,6 +33,8 @@ class Error;
class Filter; class Filter;
class MusicPipe; class MusicPipe;
class EventLoop; class EventLoop;
class Mixer;
class MixerListener;
struct music_chunk; struct music_chunk;
struct config_param; struct config_param;
struct PlayerControl; struct PlayerControl;
@ -79,7 +81,7 @@ struct AudioOutput {
* May be nullptr if none is available, or if software volume is * May be nullptr if none is available, or if software volume is
* configured. * configured.
*/ */
class Mixer *mixer; Mixer *mixer;
/** /**
* Will this output receive tags from the decoder? The * Will this output receive tags from the decoder? The
@ -424,6 +426,7 @@ extern struct notify audio_output_client_notify;
AudioOutput * AudioOutput *
audio_output_new(EventLoop &event_loop, const config_param &param, audio_output_new(EventLoop &event_loop, const config_param &param,
MixerListener &mixer_listener,
PlayerControl &pc, PlayerControl &pc,
Error &error); Error &error);

View File

@ -35,8 +35,9 @@
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
MultipleOutputs::MultipleOutputs() MultipleOutputs::MultipleOutputs(MixerListener &_mixer_listener)
:buffer(nullptr), pipe(nullptr), :mixer_listener(_mixer_listener),
buffer(nullptr), pipe(nullptr),
elapsed_time(-1) elapsed_time(-1)
{ {
} }
@ -50,10 +51,13 @@ MultipleOutputs::~MultipleOutputs()
} }
static AudioOutput * static AudioOutput *
LoadOutput(EventLoop &event_loop, PlayerControl &pc, const config_param &param) LoadOutput(EventLoop &event_loop, MixerListener &mixer_listener,
PlayerControl &pc, const config_param &param)
{ {
Error error; Error error;
AudioOutput *output = audio_output_new(event_loop, param, pc, error); AudioOutput *output = audio_output_new(event_loop, param,
mixer_listener,
pc, error);
if (output == nullptr) { if (output == nullptr) {
if (param.line > 0) if (param.line > 0)
FormatFatalError("line %i: %s", FormatFatalError("line %i: %s",
@ -72,7 +76,8 @@ MultipleOutputs::Configure(EventLoop &event_loop, PlayerControl &pc)
const config_param *param = nullptr; const config_param *param = nullptr;
while ((param = config_get_next_param(CONF_AUDIO_OUTPUT, while ((param = config_get_next_param(CONF_AUDIO_OUTPUT,
param)) != nullptr) { param)) != nullptr) {
auto output = LoadOutput(event_loop, pc, *param); auto output = LoadOutput(event_loop, mixer_listener,
pc, *param);
if (FindByName(output->name) != nullptr) if (FindByName(output->name) != nullptr)
FormatFatalError("output devices with identical " FormatFatalError("output devices with identical "
"names: %s", output->name); "names: %s", output->name);
@ -83,7 +88,8 @@ MultipleOutputs::Configure(EventLoop &event_loop, PlayerControl &pc)
if (outputs.empty()) { if (outputs.empty()) {
/* auto-detect device */ /* auto-detect device */
const config_param empty; const config_param empty;
auto output = LoadOutput(event_loop, pc, empty); auto output = LoadOutput(event_loop, mixer_listener,
pc, empty);
outputs.push_back(output); outputs.push_back(output);
} }
} }

View File

@ -38,12 +38,15 @@ struct AudioFormat;
class MusicBuffer; class MusicBuffer;
class MusicPipe; class MusicPipe;
class EventLoop; class EventLoop;
class MixerListener;
struct music_chunk; struct music_chunk;
struct PlayerControl; struct PlayerControl;
struct AudioOutput; struct AudioOutput;
class Error; class Error;
class MultipleOutputs { class MultipleOutputs {
MixerListener &mixer_listener;
std::vector<AudioOutput *> outputs; std::vector<AudioOutput *> outputs;
AudioFormat input_audio_format; AudioFormat input_audio_format;
@ -70,7 +73,7 @@ public:
* Load audio outputs from the configuration file and * Load audio outputs from the configuration file and
* initialize them. * initialize them.
*/ */
MultipleOutputs(); MultipleOutputs(MixerListener &_mixer_listener);
~MultipleOutputs(); ~MultipleOutputs();
void Configure(EventLoop &event_loop, PlayerControl &pc); void Configure(EventLoop &event_loop, PlayerControl &pc);

View File

@ -22,7 +22,6 @@
#include "mixer/MixerList.hxx" #include "mixer/MixerList.hxx"
#include "filter/FilterRegistry.hxx" #include "filter/FilterRegistry.hxx"
#include "pcm/Volume.hxx" #include "pcm/Volume.hxx"
#include "GlobalEvents.hxx"
#include "Main.hxx" #include "Main.hxx"
#include "event/Loop.hxx" #include "event/Loop.hxx"
#include "config/ConfigData.hxx" #include "config/ConfigData.hxx"
@ -35,11 +34,6 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
void
GlobalEvents::Emit(gcc_unused Event event)
{
}
const struct filter_plugin * const struct filter_plugin *
filter_plugin_by_name(gcc_unused const char *name) filter_plugin_by_name(gcc_unused const char *name)
{ {
@ -65,6 +59,7 @@ int main(int argc, gcc_unused char **argv)
Error error; 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,
config_param(), error); config_param(), error);
if (mixer == NULL) { if (mixer == NULL) {
LogError(error, "mixer_new() failed"); LogError(error, "mixer_new() failed");

View File

@ -26,7 +26,6 @@
#include "Idle.hxx" #include "Idle.hxx"
#include "Main.hxx" #include "Main.hxx"
#include "event/Loop.hxx" #include "event/Loop.hxx"
#include "GlobalEvents.hxx"
#include "IOThread.hxx" #include "IOThread.hxx"
#include "fs/Path.hxx" #include "fs/Path.hxx"
#include "AudioParser.hxx" #include "AudioParser.hxx"
@ -47,11 +46,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
void
GlobalEvents::Emit(gcc_unused Event event)
{
}
const struct filter_plugin * const struct filter_plugin *
filter_plugin_by_name(gcc_unused const char *name) filter_plugin_by_name(gcc_unused const char *name)
{ {
@ -95,7 +89,9 @@ load_audio_output(EventLoop &event_loop, const char *name)
Error error; Error error;
AudioOutput *ao = AudioOutput *ao =
audio_output_new(event_loop, *param, dummy_player_control, audio_output_new(event_loop, *param,
*(MixerListener *)nullptr,
dummy_player_control,
error); error);
if (ao == nullptr) if (ao == nullptr)
LogError(error); LogError(error);