output/Interface: define a new struct AudioOutput

Hide struct FilteredAudioOutput from the plugins, preparing for hiding
MPD's core internals.
This commit is contained in:
Max Kellermann 2017-08-07 21:55:29 +02:00
parent e11229494e
commit bea5681fd8
31 changed files with 228 additions and 178 deletions

View File

@ -1373,6 +1373,7 @@ OUTPUT_LIBS = \
OUTPUT_API_SRC = \ OUTPUT_API_SRC = \
src/output/Client.hxx \ src/output/Client.hxx \
src/output/OutputAPI.hxx \ src/output/OutputAPI.hxx \
src/output/Interface.hxx \
src/output/Filtered.cxx src/output/Filtered.hxx \ src/output/Filtered.cxx src/output/Filtered.hxx \
src/output/Wrapper.hxx \ src/output/Wrapper.hxx \
src/output/Registry.cxx src/output/Registry.hxx \ src/output/Registry.cxx src/output/Registry.hxx \
@ -2105,11 +2106,10 @@ test_run_convert_LDADD = \
libutil.a libutil.a
test_run_output_LDADD = $(MPD_LIBS) \ test_run_output_LDADD = $(MPD_LIBS) \
$(PCM_LIBS) \
$(OUTPUT_LIBS) \ $(OUTPUT_LIBS) \
$(ENCODER_LIBS) \ $(ENCODER_LIBS) \
libmixer_plugins.a \ libmixer_plugins.a \
$(FILTER_LIBS) \ $(PCM_LIBS) \
$(TAG_LIBS) \ $(TAG_LIBS) \
libconf.a \ libconf.a \
libbasic.a \ libbasic.a \
@ -2123,13 +2123,10 @@ test_run_output_LDADD = $(MPD_LIBS) \
test_run_output_SOURCES = test/run_output.cxx \ test_run_output_SOURCES = test/run_output.cxx \
src/Log.cxx src/LogBackend.cxx \ src/Log.cxx src/LogBackend.cxx \
src/output/Domain.cxx \ src/output/Domain.cxx \
src/output/Init.cxx src/output/Finish.cxx src/output/Registry.cxx \ src/output/Registry.cxx \
src/output/OutputPlugin.cxx \ src/output/OutputPlugin.cxx \
src/mixer/MixerControl.cxx \ src/mixer/MixerControl.cxx \
src/mixer/MixerType.cxx \ src/mixer/MixerType.cxx
src/filter/FilterPlugin.cxx \
src/filter/FilterConfig.cxx \
src/filter/Observer.cxx
test_read_mixer_LDADD = \ test_read_mixer_LDADD = \
libpcm.a \ libpcm.a \

View File

@ -19,6 +19,7 @@
#include "config.h" #include "config.h"
#include "Filtered.hxx" #include "Filtered.hxx"
#include "Interface.hxx"
#include "OutputPlugin.hxx" #include "OutputPlugin.hxx"
#include "Domain.hxx" #include "Domain.hxx"
#include "Log.hxx" #include "Log.hxx"
@ -31,22 +32,22 @@
bool bool
FilteredAudioOutput::SupportsEnableDisable() const noexcept FilteredAudioOutput::SupportsEnableDisable() const noexcept
{ {
assert((plugin.enable == nullptr) == (plugin.disable == nullptr)); assert((output->plugin.enable == nullptr) == (output->plugin.disable == nullptr));
return plugin.enable != nullptr; return output->plugin.enable != nullptr;
} }
bool bool
FilteredAudioOutput::SupportsPause() const noexcept FilteredAudioOutput::SupportsPause() const noexcept
{ {
return plugin.pause != nullptr; return output->plugin.pause != nullptr;
} }
void void
FilteredAudioOutput::Enable() FilteredAudioOutput::Enable()
{ {
try { try {
ao_plugin_enable(*this); ao_plugin_enable(*output);
} catch (const std::runtime_error &e) { } catch (const std::runtime_error &e) {
std::throw_with_nested(FormatRuntimeError("Failed to enable output %s", std::throw_with_nested(FormatRuntimeError("Failed to enable output %s",
GetLogName())); GetLogName()));
@ -56,7 +57,7 @@ FilteredAudioOutput::Enable()
void void
FilteredAudioOutput::Disable() noexcept FilteredAudioOutput::Disable() noexcept
{ {
ao_plugin_disable(*this); ao_plugin_disable(*output);
} }
void void
@ -76,7 +77,7 @@ FilteredAudioOutput::OpenOutputAndConvert(AudioFormat desired_audio_format)
out_audio_format = desired_audio_format; out_audio_format = desired_audio_format;
try { try {
ao_plugin_open(*this, out_audio_format); ao_plugin_open(*output, out_audio_format);
} catch (const std::runtime_error &e) { } catch (const std::runtime_error &e) {
std::throw_with_nested(FormatRuntimeError("Failed to open %s", std::throw_with_nested(FormatRuntimeError("Failed to open %s",
GetLogName())); GetLogName()));
@ -90,7 +91,7 @@ FilteredAudioOutput::OpenOutputAndConvert(AudioFormat desired_audio_format)
try { try {
ConfigureConvertFilter(); ConfigureConvertFilter();
} catch (const std::runtime_error &e) { } catch (const std::runtime_error &e) {
ao_plugin_close(*this); ao_plugin_close(*output);
if (out_audio_format.format == SampleFormat::DSD) { if (out_audio_format.format == SampleFormat::DSD) {
/* if the audio output supports DSD, but not /* if the audio output supports DSD, but not
@ -119,7 +120,7 @@ FilteredAudioOutput::CloseOutput(bool drain) noexcept
else else
Cancel(); Cancel();
ao_plugin_close(*this); ao_plugin_close(*output);
} }
void void
@ -148,31 +149,31 @@ FilteredAudioOutput::Close(bool drain) noexcept
std::chrono::steady_clock::duration std::chrono::steady_clock::duration
FilteredAudioOutput::Delay() noexcept FilteredAudioOutput::Delay() noexcept
{ {
return ao_plugin_delay(*this); return ao_plugin_delay(*output);
} }
void void
FilteredAudioOutput::SendTag(const Tag &tag) FilteredAudioOutput::SendTag(const Tag &tag)
{ {
ao_plugin_send_tag(*this, tag); ao_plugin_send_tag(*output, tag);
} }
size_t size_t
FilteredAudioOutput::Play(const void *data, size_t size) FilteredAudioOutput::Play(const void *data, size_t size)
{ {
return ao_plugin_play(*this, data, size); return ao_plugin_play(*output, data, size);
} }
void void
FilteredAudioOutput::Drain() FilteredAudioOutput::Drain()
{ {
ao_plugin_drain(*this); ao_plugin_drain(*output);
} }
void void
FilteredAudioOutput::Cancel() noexcept FilteredAudioOutput::Cancel() noexcept
{ {
ao_plugin_cancel(*this); ao_plugin_cancel(*output);
} }
void void
@ -185,7 +186,7 @@ bool
FilteredAudioOutput::IteratePause() noexcept FilteredAudioOutput::IteratePause() noexcept
{ {
try { try {
return ao_plugin_pause(*this); return ao_plugin_pause(*output);
} catch (const std::runtime_error &e) { } catch (const std::runtime_error &e) {
FormatError(e, "Failed to pause %s", FormatError(e, "Failed to pause %s",
GetLogName()); GetLogName());

View File

@ -33,7 +33,7 @@ class Mixer;
class MixerListener; class MixerListener;
struct MusicChunk; struct MusicChunk;
struct ConfigBlock; struct ConfigBlock;
struct AudioOutputPlugin; struct AudioOutput;
struct ReplayGainConfig; struct ReplayGainConfig;
struct Tag; struct Tag;
@ -54,7 +54,7 @@ public:
/** /**
* The plugin which implements this output device. * The plugin which implements this output device.
*/ */
const AudioOutputPlugin &plugin; AudioOutput *const output;
/** /**
* The #mixer object associated with this audio output device. * The #mixer object associated with this audio output device.
@ -120,18 +120,11 @@ public:
/** /**
* Throws #std::runtime_error on error. * Throws #std::runtime_error on error.
*/ */
FilteredAudioOutput(const AudioOutputPlugin &_plugin, FilteredAudioOutput(AudioOutput &_output,
const ConfigBlock &block); const ConfigBlock &block);
~FilteredAudioOutput(); ~FilteredAudioOutput();
/**
* Plugins shall call this method if they require an
* "audio_format" setting which evaluates
* AudioFormat::IsFullyDefined().
*/
void NeedFullyDefinedAudioFormat();
private: private:
void Configure(const ConfigBlock &block); void Configure(const ConfigBlock &block);

View File

@ -31,6 +31,8 @@ FilteredAudioOutput::~FilteredAudioOutput()
delete prepared_replay_gain_filter; delete prepared_replay_gain_filter;
delete prepared_other_replay_gain_filter; delete prepared_other_replay_gain_filter;
delete prepared_filter; delete prepared_filter;
ao_plugin_finish(output);
} }
void void
@ -43,5 +45,5 @@ FilteredAudioOutput::BeginDestroy() noexcept
void void
FilteredAudioOutput::FinishDestroy() noexcept FilteredAudioOutput::FinishDestroy() noexcept
{ {
ao_plugin_finish(this); ao_plugin_finish(output);
} }

View File

@ -50,25 +50,21 @@
#define AUDIO_OUTPUT_FORMAT "format" #define AUDIO_OUTPUT_FORMAT "format"
#define AUDIO_FILTERS "filters" #define AUDIO_FILTERS "filters"
FilteredAudioOutput::FilteredAudioOutput(const AudioOutputPlugin &_plugin, FilteredAudioOutput::FilteredAudioOutput(AudioOutput &_output,
const ConfigBlock &block) const ConfigBlock &block)
:plugin(_plugin) :output(&_output)
{ {
#ifndef NDEBUG
const auto &plugin = output->plugin;
assert(plugin.finish != nullptr); assert(plugin.finish != nullptr);
assert(plugin.open != nullptr); assert(plugin.open != nullptr);
assert(plugin.close != nullptr); assert(plugin.close != nullptr);
assert(plugin.play != nullptr); assert(plugin.play != nullptr);
#endif
Configure(block); Configure(block);
} }
void
FilteredAudioOutput::NeedFullyDefinedAudioFormat()
{
if (!config_audio_format.IsFullyDefined())
throw std::runtime_error("Need full audio format specification");
}
static const AudioOutputPlugin * static const AudioOutputPlugin *
audio_output_detect() audio_output_detect()
{ {
@ -176,7 +172,7 @@ FilteredAudioOutput::Configure(const ConfigBlock &block)
{ {
char buffer[64]; char buffer[64];
snprintf(buffer, sizeof(buffer), "\"%s\" (%s)", snprintf(buffer, sizeof(buffer), "\"%s\" (%s)",
name, plugin.name); name, output->plugin.name);
log_name = buffer; log_name = buffer;
} }
@ -211,6 +207,9 @@ FilteredAudioOutput::Setup(EventLoop &event_loop,
MixerListener &mixer_listener, MixerListener &mixer_listener,
const ConfigBlock &block) const ConfigBlock &block)
{ {
if (output->need_fully_defined_audio_format &&
!config_audio_format.IsFullyDefined())
throw std::runtime_error("Need full audio format specification");
/* create the replay_gain filter */ /* create the replay_gain filter */
@ -234,7 +233,7 @@ FilteredAudioOutput::Setup(EventLoop &event_loop,
try { try {
mixer = audio_output_load_mixer(event_loop, *this, block, mixer = audio_output_load_mixer(event_loop, *this, block,
plugin.mixer_plugin, output->plugin.mixer_plugin,
*prepared_filter, *prepared_filter,
mixer_listener); mixer_listener);
} catch (const std::runtime_error &e) { } catch (const std::runtime_error &e) {
@ -295,13 +294,22 @@ audio_output_new(EventLoop &event_loop,
auto *ao = ao_plugin_init(event_loop, *plugin, block); auto *ao = ao_plugin_init(event_loop, *plugin, block);
assert(ao != nullptr); assert(ao != nullptr);
FilteredAudioOutput *f;
try { try {
ao->Setup(event_loop, replay_gain_config, f = new FilteredAudioOutput(*ao, block);
mixer_listener, block);
} catch (...) { } catch (...) {
ao_plugin_finish(ao); ao_plugin_finish(ao);
throw; throw;
} }
return ao; try {
f->Setup(event_loop, replay_gain_config,
mixer_listener, block);
} catch (...) {
delete f;
throw;
}
return f;
} }

49
src/output/Interface.hxx Normal file
View File

@ -0,0 +1,49 @@
/*
* Copyright 2003-2017 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_AUDIO_OUTPUT_INTERFACE_HXX
#define MPD_AUDIO_OUTPUT_INTERFACE_HXX
struct AudioOutputPlugin;
struct FilteredAudioOutput;
struct AudioOutput {
/**
* The plugin which implements this output device.
*/
const AudioOutputPlugin &plugin;
FilteredAudioOutput *parent;
bool need_fully_defined_audio_format = false;
AudioOutput(const AudioOutputPlugin &_plugin)
:plugin(_plugin) {}
/**
* Plugins shall call this method if they require an
* "audio_format" setting which evaluates
* AudioFormat::IsFullyDefined().
*/
void NeedFullyDefinedAudioFormat() {
need_fully_defined_audio_format = true;
}
};
#endif

View File

@ -23,7 +23,7 @@
// IWYU pragma: begin_exports // IWYU pragma: begin_exports
#include "OutputPlugin.hxx" #include "OutputPlugin.hxx"
#include "Filtered.hxx" #include "Interface.hxx"
#include "AudioFormat.hxx" #include "AudioFormat.hxx"
#include "tag/Tag.hxx" #include "tag/Tag.hxx"
#include "config/Block.hxx" #include "config/Block.hxx"

View File

@ -19,9 +19,11 @@
#include "config.h" #include "config.h"
#include "OutputPlugin.hxx" #include "OutputPlugin.hxx"
#include "Filtered.hxx" #include "Interface.hxx"
FilteredAudioOutput * #include <assert.h>
AudioOutput *
ao_plugin_init(EventLoop &event_loop, ao_plugin_init(EventLoop &event_loop,
const AudioOutputPlugin &plugin, const AudioOutputPlugin &plugin,
const ConfigBlock &block) const ConfigBlock &block)
@ -32,39 +34,39 @@ ao_plugin_init(EventLoop &event_loop,
} }
void void
ao_plugin_finish(FilteredAudioOutput *ao) noexcept ao_plugin_finish(AudioOutput *ao) noexcept
{ {
ao->plugin.finish(ao); ao->plugin.finish(ao);
} }
void void
ao_plugin_enable(FilteredAudioOutput &ao) ao_plugin_enable(AudioOutput &ao)
{ {
if (ao.plugin.enable != nullptr) if (ao.plugin.enable != nullptr)
ao.plugin.enable(&ao); ao.plugin.enable(&ao);
} }
void void
ao_plugin_disable(FilteredAudioOutput &ao) noexcept ao_plugin_disable(AudioOutput &ao) noexcept
{ {
if (ao.plugin.disable != nullptr) if (ao.plugin.disable != nullptr)
ao.plugin.disable(&ao); ao.plugin.disable(&ao);
} }
void void
ao_plugin_open(FilteredAudioOutput &ao, AudioFormat &audio_format) ao_plugin_open(AudioOutput &ao, AudioFormat &audio_format)
{ {
ao.plugin.open(&ao, audio_format); ao.plugin.open(&ao, audio_format);
} }
void void
ao_plugin_close(FilteredAudioOutput &ao) noexcept ao_plugin_close(AudioOutput &ao) noexcept
{ {
ao.plugin.close(&ao); ao.plugin.close(&ao);
} }
std::chrono::steady_clock::duration std::chrono::steady_clock::duration
ao_plugin_delay(FilteredAudioOutput &ao) noexcept ao_plugin_delay(AudioOutput &ao) noexcept
{ {
return ao.plugin.delay != nullptr return ao.plugin.delay != nullptr
? ao.plugin.delay(&ao) ? ao.plugin.delay(&ao)
@ -72,34 +74,34 @@ ao_plugin_delay(FilteredAudioOutput &ao) noexcept
} }
void void
ao_plugin_send_tag(FilteredAudioOutput &ao, const Tag &tag) ao_plugin_send_tag(AudioOutput &ao, const Tag &tag)
{ {
if (ao.plugin.send_tag != nullptr) if (ao.plugin.send_tag != nullptr)
ao.plugin.send_tag(&ao, tag); ao.plugin.send_tag(&ao, tag);
} }
size_t size_t
ao_plugin_play(FilteredAudioOutput &ao, const void *chunk, size_t size) ao_plugin_play(AudioOutput &ao, const void *chunk, size_t size)
{ {
return ao.plugin.play(&ao, chunk, size); return ao.plugin.play(&ao, chunk, size);
} }
void void
ao_plugin_drain(FilteredAudioOutput &ao) ao_plugin_drain(AudioOutput &ao)
{ {
if (ao.plugin.drain != nullptr) if (ao.plugin.drain != nullptr)
ao.plugin.drain(&ao); ao.plugin.drain(&ao);
} }
void void
ao_plugin_cancel(FilteredAudioOutput &ao) noexcept ao_plugin_cancel(AudioOutput &ao) noexcept
{ {
if (ao.plugin.cancel != nullptr) if (ao.plugin.cancel != nullptr)
ao.plugin.cancel(&ao); ao.plugin.cancel(&ao);
} }
bool bool
ao_plugin_pause(FilteredAudioOutput &ao) ao_plugin_pause(AudioOutput &ao)
{ {
return ao.plugin.pause != nullptr && ao.plugin.pause(&ao); return ao.plugin.pause != nullptr && ao.plugin.pause(&ao);
} }

View File

@ -29,7 +29,7 @@
struct ConfigBlock; struct ConfigBlock;
struct AudioFormat; struct AudioFormat;
struct Tag; struct Tag;
struct FilteredAudioOutput; struct AudioOutput;
struct MixerPlugin; struct MixerPlugin;
class EventLoop; class EventLoop;
@ -57,12 +57,12 @@ struct AudioOutputPlugin {
* @param param the configuration section, or nullptr if there is * @param param the configuration section, or nullptr if there is
* no configuration * no configuration
*/ */
FilteredAudioOutput *(*init)(EventLoop &event_loop, const ConfigBlock &block); AudioOutput *(*init)(EventLoop &event_loop, const ConfigBlock &block);
/** /**
* Free resources allocated by this device. * Free resources allocated by this device.
*/ */
void (*finish)(FilteredAudioOutput *data); void (*finish)(AudioOutput *data);
/** /**
* Enable the device. This may allocate resources, preparing * Enable the device. This may allocate resources, preparing
@ -70,13 +70,13 @@ struct AudioOutputPlugin {
* *
* Throws #std::runtime_error on error. * Throws #std::runtime_error on error.
*/ */
void (*enable)(FilteredAudioOutput *data); void (*enable)(AudioOutput *data);
/** /**
* Disables the device. It is closed before this method is * Disables the device. It is closed before this method is
* called. * called.
*/ */
void (*disable)(FilteredAudioOutput *data); void (*disable)(AudioOutput *data);
/** /**
* Really open the device. * Really open the device.
@ -86,12 +86,12 @@ struct AudioOutputPlugin {
* @param audio_format the audio format in which data is going * @param audio_format the audio format in which data is going
* to be delivered; may be modified by the plugin * to be delivered; may be modified by the plugin
*/ */
void (*open)(FilteredAudioOutput *data, AudioFormat &audio_format); void (*open)(AudioOutput *data, AudioFormat &audio_format);
/** /**
* Close the device. * Close the device.
*/ */
void (*close)(FilteredAudioOutput *data); void (*close)(AudioOutput *data);
/** /**
* Returns a positive number if the output thread shall further * Returns a positive number if the output thread shall further
@ -102,13 +102,13 @@ struct AudioOutputPlugin {
* *
* @return the duration to wait * @return the duration to wait
*/ */
std::chrono::steady_clock::duration (*delay)(FilteredAudioOutput *data) noexcept; std::chrono::steady_clock::duration (*delay)(AudioOutput *data) noexcept;
/** /**
* Display metadata for the next chunk. Optional method, * Display metadata for the next chunk. Optional method,
* because not all devices can display metadata. * because not all devices can display metadata.
*/ */
void (*send_tag)(FilteredAudioOutput *data, const Tag &tag); void (*send_tag)(AudioOutput *data, const Tag &tag);
/** /**
* Play a chunk of audio data. * Play a chunk of audio data.
@ -117,19 +117,19 @@ struct AudioOutputPlugin {
* *
* @return the number of bytes played * @return the number of bytes played
*/ */
size_t (*play)(FilteredAudioOutput *data, size_t (*play)(AudioOutput *data,
const void *chunk, size_t size); const void *chunk, size_t size);
/** /**
* Wait until the device has finished playing. * Wait until the device has finished playing.
*/ */
void (*drain)(FilteredAudioOutput *data); void (*drain)(AudioOutput *data);
/** /**
* Try to cancel data which may still be in the device's * Try to cancel data which may still be in the device's
* buffers. * buffers.
*/ */
void (*cancel)(FilteredAudioOutput *data); void (*cancel)(AudioOutput *data);
/** /**
* Pause the device. If supported, it may perform a special * Pause the device. If supported, it may perform a special
@ -142,7 +142,7 @@ struct AudioOutputPlugin {
* @return false on error (output will be closed by caller), * @return false on error (output will be closed by caller),
* true for continue to pause * true for continue to pause
*/ */
bool (*pause)(FilteredAudioOutput *data); bool (*pause)(AudioOutput *data);
/** /**
* The mixer plugin associated with this output plugin. This * The mixer plugin associated with this output plugin. This
@ -162,43 +162,43 @@ ao_plugin_test_default_device(const AudioOutputPlugin *plugin)
} }
gcc_malloc gcc_malloc
FilteredAudioOutput * AudioOutput *
ao_plugin_init(EventLoop &event_loop, ao_plugin_init(EventLoop &event_loop,
const AudioOutputPlugin &plugin, const AudioOutputPlugin &plugin,
const ConfigBlock &block); const ConfigBlock &block);
void void
ao_plugin_finish(FilteredAudioOutput *ao) noexcept; ao_plugin_finish(AudioOutput *ao) noexcept;
void void
ao_plugin_enable(FilteredAudioOutput &ao); ao_plugin_enable(AudioOutput &ao);
void void
ao_plugin_disable(FilteredAudioOutput &ao) noexcept; ao_plugin_disable(AudioOutput &ao) noexcept;
void void
ao_plugin_open(FilteredAudioOutput &ao, AudioFormat &audio_format); ao_plugin_open(AudioOutput &ao, AudioFormat &audio_format);
void void
ao_plugin_close(FilteredAudioOutput &ao) noexcept; ao_plugin_close(AudioOutput &ao) noexcept;
gcc_pure gcc_pure
std::chrono::steady_clock::duration std::chrono::steady_clock::duration
ao_plugin_delay(FilteredAudioOutput &ao) noexcept; ao_plugin_delay(AudioOutput &ao) noexcept;
void void
ao_plugin_send_tag(FilteredAudioOutput &ao, const Tag &tag); ao_plugin_send_tag(AudioOutput &ao, const Tag &tag);
size_t size_t
ao_plugin_play(FilteredAudioOutput &ao, const void *chunk, size_t size); ao_plugin_play(AudioOutput &ao, const void *chunk, size_t size);
void void
ao_plugin_drain(FilteredAudioOutput &ao); ao_plugin_drain(AudioOutput &ao);
void void
ao_plugin_cancel(FilteredAudioOutput &ao) noexcept; ao_plugin_cancel(AudioOutput &ao) noexcept;
bool bool
ao_plugin_pause(FilteredAudioOutput &ao); ao_plugin_pause(AudioOutput &ao);
#endif #endif

View File

@ -20,78 +20,79 @@
#ifndef MPD_OUTPUT_WRAPPER_HXX #ifndef MPD_OUTPUT_WRAPPER_HXX
#define MPD_OUTPUT_WRAPPER_HXX #define MPD_OUTPUT_WRAPPER_HXX
#include "Filtered.hxx" #include "Interface.hxx"
#include "util/Cast.hxx" #include "util/Cast.hxx"
#include <chrono> #include <chrono>
struct ConfigBlock; struct ConfigBlock;
struct AudioFormat;
struct Tag; struct Tag;
template<class T> template<class T>
struct AudioOutputWrapper { struct AudioOutputWrapper {
static T &Cast(FilteredAudioOutput &ao) { static T &Cast(AudioOutput &ao) {
return ContainerCast(ao, &T::base); return ContainerCast(ao, &T::base);
} }
static FilteredAudioOutput *Init(EventLoop &event_loop, static AudioOutput *Init(EventLoop &event_loop,
const ConfigBlock &block) { const ConfigBlock &block) {
T *t = T::Create(event_loop, block); T *t = T::Create(event_loop, block);
return &t->base; return &t->base;
} }
static void Finish(FilteredAudioOutput *ao) { static void Finish(AudioOutput *ao) {
T *t = &Cast(*ao); T *t = &Cast(*ao);
delete t; delete t;
} }
static void Enable(FilteredAudioOutput *ao) { static void Enable(AudioOutput *ao) {
T &t = Cast(*ao); T &t = Cast(*ao);
t.Enable(); t.Enable();
} }
static void Disable(FilteredAudioOutput *ao) { static void Disable(AudioOutput *ao) {
T &t = Cast(*ao); T &t = Cast(*ao);
t.Disable(); t.Disable();
} }
static void Open(FilteredAudioOutput *ao, AudioFormat &audio_format) { static void Open(AudioOutput *ao, AudioFormat &audio_format) {
T &t = Cast(*ao); T &t = Cast(*ao);
t.Open(audio_format); t.Open(audio_format);
} }
static void Close(FilteredAudioOutput *ao) { static void Close(AudioOutput *ao) {
T &t = Cast(*ao); T &t = Cast(*ao);
t.Close(); t.Close();
} }
gcc_pure gcc_pure
static std::chrono::steady_clock::duration Delay(FilteredAudioOutput *ao) noexcept { static std::chrono::steady_clock::duration Delay(AudioOutput *ao) noexcept {
T &t = Cast(*ao); T &t = Cast(*ao);
return t.Delay(); return t.Delay();
} }
static void SendTag(FilteredAudioOutput *ao, const Tag &tag) { static void SendTag(AudioOutput *ao, const Tag &tag) {
T &t = Cast(*ao); T &t = Cast(*ao);
t.SendTag(tag); t.SendTag(tag);
} }
static size_t Play(FilteredAudioOutput *ao, const void *chunk, size_t size) { static size_t Play(AudioOutput *ao, const void *chunk, size_t size) {
T &t = Cast(*ao); T &t = Cast(*ao);
return t.Play(chunk, size); return t.Play(chunk, size);
} }
static void Drain(FilteredAudioOutput *ao) { static void Drain(AudioOutput *ao) {
T &t = Cast(*ao); T &t = Cast(*ao);
t.Drain(); t.Drain();
} }
static void Cancel(FilteredAudioOutput *ao) { static void Cancel(AudioOutput *ao) {
T &t = Cast(*ao); T &t = Cast(*ao);
t.Cancel(); t.Cancel();
} }
static bool Pause(FilteredAudioOutput *ao) { static bool Pause(AudioOutput *ao) {
T &t = Cast(*ao); T &t = Cast(*ao);
return t.Pause(); return t.Pause();
} }

View File

@ -64,7 +64,7 @@ class AlsaOutput final
friend struct AudioOutputWrapper<AlsaOutput>; friend struct AudioOutputWrapper<AlsaOutput>;
FilteredAudioOutput base; AudioOutput base;
Manual<PcmExport> pcm_export; Manual<PcmExport> pcm_export;
@ -414,7 +414,7 @@ static constexpr Domain alsa_output_domain("alsa_output");
AlsaOutput::AlsaOutput(EventLoop &loop, const ConfigBlock &block) AlsaOutput::AlsaOutput(EventLoop &loop, const ConfigBlock &block)
:MultiSocketMonitor(loop), DeferredMonitor(loop), :MultiSocketMonitor(loop), DeferredMonitor(loop),
base(alsa_output_plugin, block), base(alsa_output_plugin),
device(block.GetBlockValue("device", "")), device(block.GetBlockValue("device", "")),
#ifdef ENABLE_DSD #ifdef ENABLE_DSD
dop(block.GetBlockValue("dop", false) || dop(block.GetBlockValue("dop", false) ||

View File

@ -40,7 +40,7 @@ static unsigned ao_output_ref;
class AoOutput { class AoOutput {
friend struct AudioOutputWrapper<AoOutput>; friend struct AudioOutputWrapper<AoOutput>;
FilteredAudioOutput base; AudioOutput base;
const size_t write_size; const size_t write_size;
int driver; int driver;
@ -95,7 +95,7 @@ MakeAoError()
} }
AoOutput::AoOutput(const ConfigBlock &block) AoOutput::AoOutput(const ConfigBlock &block)
:base(ao_output_plugin, block), :base(ao_output_plugin),
write_size(block.GetBlockValue("write_size", 1024u)) write_size(block.GetBlockValue("write_size", 1024u))
{ {
if (ao_output_ref == 0) { if (ao_output_ref == 0) {

View File

@ -37,7 +37,7 @@
class FifoOutput { class FifoOutput {
friend struct AudioOutputWrapper<FifoOutput>; friend struct AudioOutputWrapper<FifoOutput>;
FilteredAudioOutput base; AudioOutput base;
const AllocatedPath path; const AllocatedPath path;
std::string path_utf8; std::string path_utf8;
@ -75,7 +75,7 @@ public:
static constexpr Domain fifo_output_domain("fifo_output"); static constexpr Domain fifo_output_domain("fifo_output");
FifoOutput::FifoOutput(const ConfigBlock &block) FifoOutput::FifoOutput(const ConfigBlock &block)
:base(fifo_output_plugin, block), :base(fifo_output_plugin),
path(block.GetPath("path")) path(block.GetPath("path"))
{ {
if (path.IsNull()) if (path.IsNull())

View File

@ -48,7 +48,7 @@ class HaikuOutput {
friend int haiku_output_get_volume(HaikuOutput &haiku); friend int haiku_output_get_volume(HaikuOutput &haiku);
friend bool haiku_output_set_volume(HaikuOutput &haiku, unsigned volume); friend bool haiku_output_set_volume(HaikuOutput &haiku, unsigned volume);
FilteredAudioOutput base; AudioOutput base;
size_t write_size; size_t write_size;
@ -66,7 +66,7 @@ class HaikuOutput {
public: public:
HaikuOutput(const ConfigBlock &block) HaikuOutput(const ConfigBlock &block)
:base(haiku_output_plugin, block), :base(haiku_output_plugin),
/* XXX: by default we should let the MediaKit propose the buffer size */ /* XXX: by default we should let the MediaKit propose the buffer size */
write_size(block.GetBlockValue("write_size", 4096u)) {} write_size(block.GetBlockValue("write_size", 4096u)) {}

View File

@ -43,7 +43,7 @@ static constexpr unsigned MAX_PORTS = 16;
static constexpr size_t jack_sample_size = sizeof(jack_default_audio_sample_t); static constexpr size_t jack_sample_size = sizeof(jack_default_audio_sample_t);
struct JackOutput { struct JackOutput {
FilteredAudioOutput base; AudioOutput base;
/** /**
* libjack options passed to jack_client_open(). * libjack options passed to jack_client_open().
@ -162,7 +162,7 @@ parse_port_list(const char *source, std::string dest[])
} }
JackOutput::JackOutput(const ConfigBlock &block) JackOutput::JackOutput(const ConfigBlock &block)
:base(jack_output_plugin, block), :base(jack_output_plugin),
name(block.GetBlockValue("client_name", nullptr)), name(block.GetBlockValue("client_name", nullptr)),
server_name(block.GetBlockValue("server_name", nullptr)) server_name(block.GetBlockValue("server_name", nullptr))
{ {
@ -443,7 +443,7 @@ JackOutput::Disable()
} }
} }
static FilteredAudioOutput * static AudioOutput *
mpd_jack_init(EventLoop &, const ConfigBlock &block) mpd_jack_init(EventLoop &, const ConfigBlock &block)
{ {
jack_set_error_function(mpd_jack_error); jack_set_error_function(mpd_jack_error);

View File

@ -26,7 +26,7 @@
class NullOutput { class NullOutput {
friend struct AudioOutputWrapper<NullOutput>; friend struct AudioOutputWrapper<NullOutput>;
FilteredAudioOutput base; AudioOutput base;
const bool sync; const bool sync;
@ -34,7 +34,7 @@ class NullOutput {
public: public:
NullOutput(const ConfigBlock &block) NullOutput(const ConfigBlock &block)
:base(null_output_plugin, block), :base(null_output_plugin),
sync(block.GetBlockValue("sync", true)) {} sync(block.GetBlockValue("sync", true)) {}
static NullOutput *Create(EventLoop &event_loop, static NullOutput *Create(EventLoop &event_loop,

View File

@ -36,7 +36,7 @@
#include <memory> #include <memory>
struct OSXOutput { struct OSXOutput {
FilteredAudioOutput base; AudioOutput base;
/* configuration settings */ /* configuration settings */
OSType component_subtype; OSType component_subtype;
@ -80,7 +80,7 @@ osx_output_test_default_device(void)
} }
OSXOutput::OSXOutput(const ConfigBlock &block) OSXOutput::OSXOutput(const ConfigBlock &block)
:base(osx_output_plugin, block) :base(osx_output_plugin)
{ {
const char *device = block.GetBlockValue("device"); const char *device = block.GetBlockValue("device");
@ -103,7 +103,7 @@ OSXOutput::OSXOutput(const ConfigBlock &block)
sync_sample_rate = block.GetBlockValue("sync_sample_rate", false); sync_sample_rate = block.GetBlockValue("sync_sample_rate", false);
} }
static FilteredAudioOutput * static AudioOutput *
osx_output_init(EventLoop &, const ConfigBlock &block) osx_output_init(EventLoop &, const ConfigBlock &block)
{ {
OSXOutput *oo = new OSXOutput(block); OSXOutput *oo = new OSXOutput(block);
@ -128,7 +128,7 @@ osx_output_init(EventLoop &, const ConfigBlock &block)
} }
static void static void
osx_output_finish(FilteredAudioOutput *ao) osx_output_finish(AudioOutput *ao)
{ {
OSXOutput *oo = (OSXOutput *)ao; OSXOutput *oo = (OSXOutput *)ao;
@ -514,7 +514,7 @@ osx_render(void *vdata,
} }
static void static void
osx_output_enable(FilteredAudioOutput *ao) osx_output_enable(AudioOutput *ao)
{ {
char errormsg[1024]; char errormsg[1024];
OSXOutput *oo = (OSXOutput *)ao; OSXOutput *oo = (OSXOutput *)ao;
@ -550,7 +550,7 @@ osx_output_enable(FilteredAudioOutput *ao)
} }
static void static void
osx_output_disable(FilteredAudioOutput *ao) osx_output_disable(AudioOutput *ao)
{ {
OSXOutput *oo = (OSXOutput *)ao; OSXOutput *oo = (OSXOutput *)ao;
@ -562,7 +562,7 @@ osx_output_disable(FilteredAudioOutput *ao)
} }
static void static void
osx_output_close(FilteredAudioOutput *ao) osx_output_close(AudioOutput *ao)
{ {
OSXOutput *od = (OSXOutput *)ao; OSXOutput *od = (OSXOutput *)ao;
@ -573,7 +573,7 @@ osx_output_close(FilteredAudioOutput *ao)
} }
static void static void
osx_output_open(FilteredAudioOutput *ao, AudioFormat &audio_format) osx_output_open(AudioOutput *ao, AudioFormat &audio_format)
{ {
char errormsg[1024]; char errormsg[1024];
OSXOutput *od = (OSXOutput *)ao; OSXOutput *od = (OSXOutput *)ao;
@ -663,14 +663,14 @@ osx_output_open(FilteredAudioOutput *ao, AudioFormat &audio_format)
} }
static size_t static size_t
osx_output_play(FilteredAudioOutput *ao, const void *chunk, size_t size) osx_output_play(AudioOutput *ao, const void *chunk, size_t size)
{ {
OSXOutput *od = (OSXOutput *)ao; OSXOutput *od = (OSXOutput *)ao;
return od->ring_buffer->push((uint8_t *)chunk, size); return od->ring_buffer->push((uint8_t *)chunk, size);
} }
static std::chrono::steady_clock::duration static std::chrono::steady_clock::duration
osx_output_delay(FilteredAudioOutput *ao) noexcept osx_output_delay(AudioOutput *ao) noexcept
{ {
OSXOutput *od = (OSXOutput *)ao; OSXOutput *od = (OSXOutput *)ao;
return od->ring_buffer->write_available() return od->ring_buffer->write_available()

View File

@ -39,7 +39,7 @@ class OpenALOutput {
/* should be enough for buffer size = 2048 */ /* should be enough for buffer size = 2048 */
static constexpr unsigned NUM_BUFFERS = 16; static constexpr unsigned NUM_BUFFERS = 16;
FilteredAudioOutput base; AudioOutput base;
const char *device_name; const char *device_name;
ALCdevice *device; ALCdevice *device;
@ -138,7 +138,7 @@ OpenALOutput::SetupContext()
} }
OpenALOutput::OpenALOutput(const ConfigBlock &block) OpenALOutput::OpenALOutput(const ConfigBlock &block)
:base(openal_output_plugin, block), :base(openal_output_plugin),
device_name(block.GetBlockValue("device")) device_name(block.GetBlockValue("device"))
{ {
if (device_name == nullptr) if (device_name == nullptr)

View File

@ -63,7 +63,7 @@
class OssOutput { class OssOutput {
friend struct AudioOutputWrapper<OssOutput>; friend struct AudioOutputWrapper<OssOutput>;
FilteredAudioOutput base; AudioOutput base;
#ifdef AFMT_S24_PACKED #ifdef AFMT_S24_PACKED
Manual<PcmExport> pcm_export; Manual<PcmExport> pcm_export;
@ -85,8 +85,8 @@ class OssOutput {
int oss_format; int oss_format;
public: public:
OssOutput(const ConfigBlock &block, const char *_device=nullptr) explicit OssOutput(const char *_device=nullptr)
:base(oss_output_plugin, block), :base(oss_output_plugin),
fd(-1), device(_device) {} fd(-1), device(_device) {}
static OssOutput *Create(EventLoop &event_loop, static OssOutput *Create(EventLoop &event_loop,
@ -192,11 +192,10 @@ oss_open_default()
int err[ARRAY_SIZE(default_devices)]; int err[ARRAY_SIZE(default_devices)];
enum oss_stat ret[ARRAY_SIZE(default_devices)]; enum oss_stat ret[ARRAY_SIZE(default_devices)];
const ConfigBlock empty;
for (int i = ARRAY_SIZE(default_devices); --i >= 0; ) { for (int i = ARRAY_SIZE(default_devices); --i >= 0; ) {
ret[i] = oss_stat_device(default_devices[i], &err[i]); ret[i] = oss_stat_device(default_devices[i], &err[i]);
if (ret[i] == OSS_STAT_NO_ERROR) if (ret[i] == OSS_STAT_NO_ERROR)
return new OssOutput(empty, default_devices[i]); return new OssOutput(default_devices[i]);
} }
for (int i = ARRAY_SIZE(default_devices); --i >= 0; ) { for (int i = ARRAY_SIZE(default_devices); --i >= 0; ) {
@ -231,7 +230,7 @@ OssOutput::Create(EventLoop &, const ConfigBlock &block)
{ {
const char *device = block.GetBlockValue("device"); const char *device = block.GetBlockValue("device");
if (device != nullptr) if (device != nullptr)
return new OssOutput(block, device); return new OssOutput(device);
return oss_open_default(); return oss_open_default();
} }

View File

@ -31,7 +31,7 @@
class PipeOutput { class PipeOutput {
friend struct AudioOutputWrapper<PipeOutput>; friend struct AudioOutputWrapper<PipeOutput>;
FilteredAudioOutput base; AudioOutput base;
const std::string cmd; const std::string cmd;
FILE *fh; FILE *fh;
@ -52,7 +52,7 @@ public:
}; };
PipeOutput::PipeOutput(const ConfigBlock &block) PipeOutput::PipeOutput(const ConfigBlock &block)
:base(pipe_output_plugin, block), :base(pipe_output_plugin),
cmd(block.GetBlockValue("command", "")) cmd(block.GetBlockValue("command", ""))
{ {
if (cmd.empty()) if (cmd.empty())

View File

@ -47,7 +47,7 @@
class PulseOutput { class PulseOutput {
friend struct AudioOutputWrapper<PulseOutput>; friend struct AudioOutputWrapper<PulseOutput>;
FilteredAudioOutput base; AudioOutput base;
const char *name; const char *name;
const char *server; const char *server;
@ -179,7 +179,7 @@ private:
}; };
PulseOutput::PulseOutput(const ConfigBlock &block) PulseOutput::PulseOutput(const ConfigBlock &block)
:base(pulse_output_plugin, block), :base(pulse_output_plugin),
name(block.GetBlockValue("name", "mpd_pulse")), name(block.GetBlockValue("name", "mpd_pulse")),
server(block.GetBlockValue("server")), server(block.GetBlockValue("server")),
sink(block.GetBlockValue("sink")) sink(block.GetBlockValue("sink"))

View File

@ -45,7 +45,7 @@ static constexpr Domain recorder_domain("recorder");
class RecorderOutput { class RecorderOutput {
friend struct AudioOutputWrapper<RecorderOutput>; friend struct AudioOutputWrapper<RecorderOutput>;
FilteredAudioOutput base; AudioOutput base;
/** /**
* The configured encoder plugin. * The configured encoder plugin.
@ -114,7 +114,7 @@ private:
}; };
RecorderOutput::RecorderOutput(const ConfigBlock &block) RecorderOutput::RecorderOutput(const ConfigBlock &block)
:base(recorder_output_plugin, block) :base(recorder_output_plugin)
{ {
/* read configuration */ /* read configuration */

View File

@ -39,7 +39,7 @@
class RoarOutput { class RoarOutput {
friend struct AudioOutputWrapper<RoarOutput>; friend struct AudioOutputWrapper<RoarOutput>;
FilteredAudioOutput base; AudioOutput base;
const std::string host, name; const std::string host, name;
@ -54,7 +54,7 @@ class RoarOutput {
public: public:
RoarOutput(const ConfigBlock &block); RoarOutput(const ConfigBlock &block);
operator FilteredAudioOutput *() { operator AudioOutput *() {
return &base; return &base;
} }
@ -86,7 +86,7 @@ GetConfiguredRole(const ConfigBlock &block) noexcept
} }
RoarOutput::RoarOutput(const ConfigBlock &block) RoarOutput::RoarOutput(const ConfigBlock &block)
:base(roar_output_plugin, block), :base(roar_output_plugin),
host(block.GetBlockValue("server", "")), host(block.GetBlockValue("server", "")),
name(block.GetBlockValue("name", "MPD")), name(block.GetBlockValue("name", "MPD")),
role(GetConfiguredRole(block)) role(GetConfiguredRole(block))

View File

@ -40,7 +40,7 @@
static constexpr unsigned DEFAULT_CONN_TIMEOUT = 2; static constexpr unsigned DEFAULT_CONN_TIMEOUT = 2;
struct ShoutOutput final { struct ShoutOutput final {
FilteredAudioOutput base; AudioOutput base;
shout_t *shout_conn; shout_t *shout_conn;
shout_metadata_t *shout_meta; shout_metadata_t *shout_meta;
@ -113,7 +113,7 @@ ShoutSetAudioInfo(shout_t *shout_conn, const AudioFormat &audio_format)
} }
ShoutOutput::ShoutOutput(const ConfigBlock &block) ShoutOutput::ShoutOutput(const ConfigBlock &block)
:base(shout_output_plugin, block), :base(shout_output_plugin),
shout_conn(shout_new()), shout_conn(shout_new()),
shout_meta(shout_metadata_new()) shout_meta(shout_metadata_new())
{ {

View File

@ -47,7 +47,7 @@ static constexpr Domain sndio_output_domain("sndio_output");
class SndioOutput { class SndioOutput {
friend struct AudioOutputWrapper<SndioOutput>; friend struct AudioOutputWrapper<SndioOutput>;
FilteredAudioOutput base; AudioOutput base;
const char *const device; const char *const device;
const unsigned buffer_time; /* in ms */ const unsigned buffer_time; /* in ms */
struct sio_hdl *sio_hdl; struct sio_hdl *sio_hdl;
@ -65,7 +65,7 @@ public:
}; };
SndioOutput::SndioOutput(const ConfigBlock &block) SndioOutput::SndioOutput(const ConfigBlock &block)
:base(sndio_output_plugin, block), :base(sndio_output_plugin),
device(block.GetBlockValue("device", SIO_DEVANY)), device(block.GetBlockValue("device", SIO_DEVANY)),
buffer_time(block.GetBlockValue("buffer_time", buffer_time(block.GetBlockValue("buffer_time",
MPD_SNDIO_BUFFER_TIME_MS)) MPD_SNDIO_BUFFER_TIME_MS))

View File

@ -53,7 +53,7 @@ struct audio_info {
class SolarisOutput { class SolarisOutput {
friend struct AudioOutputWrapper<SolarisOutput>; friend struct AudioOutputWrapper<SolarisOutput>;
FilteredAudioOutput base; AudioOutput base;
/* configuration */ /* configuration */
const char *const device; const char *const device;
@ -61,7 +61,7 @@ class SolarisOutput {
int fd; int fd;
explicit SolarisOutput(const ConfigBlock &block) explicit SolarisOutput(const ConfigBlock &block)
:base(solaris_output_plugin, block), :base(solaris_output_plugin),
device(block.GetBlockValue("device", "/dev/audio")) {} device(block.GetBlockValue("device", "/dev/audio")) {}
public: public:

View File

@ -42,7 +42,7 @@ struct WinmmBuffer {
class WinmmOutput { class WinmmOutput {
friend struct AudioOutputWrapper<WinmmOutput>; friend struct AudioOutputWrapper<WinmmOutput>;
FilteredAudioOutput base; AudioOutput base;
const UINT device_id; const UINT device_id;
HWAVEOUT handle; HWAVEOUT handle;
@ -148,7 +148,7 @@ get_device_id(const char *device_name)
} }
WinmmOutput::WinmmOutput(const ConfigBlock &block) WinmmOutput::WinmmOutput(const ConfigBlock &block)
:base(winmm_output_plugin, block), :base(winmm_output_plugin),
device_id(get_device_id(block.GetBlockValue("device"))) device_id(get_device_id(block.GetBlockValue("device")))
{ {
} }

View File

@ -52,7 +52,7 @@ struct Tag;
class HttpdOutput final : ServerSocket, DeferredMonitor { class HttpdOutput final : ServerSocket, DeferredMonitor {
friend struct AudioOutputWrapper<HttpdOutput>; friend struct AudioOutputWrapper<HttpdOutput>;
FilteredAudioOutput base; AudioOutput base;
/** /**
* True if the audio output is open and accepts client * True if the audio output is open and accepts client
@ -160,7 +160,7 @@ public:
static HttpdOutput *Create(EventLoop &event_loop, static HttpdOutput *Create(EventLoop &event_loop,
const ConfigBlock &block); const ConfigBlock &block);
static constexpr HttpdOutput *Cast(FilteredAudioOutput *ao) { static constexpr HttpdOutput *Cast(AudioOutput *ao) {
return &ContainerCast(*ao, &HttpdOutput::base); return &ContainerCast(*ao, &HttpdOutput::base);
} }

View File

@ -51,7 +51,7 @@ const Domain httpd_output_domain("httpd_output");
inline inline
HttpdOutput::HttpdOutput(EventLoop &_loop, const ConfigBlock &block) HttpdOutput::HttpdOutput(EventLoop &_loop, const ConfigBlock &block)
:ServerSocket(_loop), DeferredMonitor(_loop), :ServerSocket(_loop), DeferredMonitor(_loop),
base(httpd_output_plugin, block), base(httpd_output_plugin),
encoder(nullptr), unflushed_input(0), encoder(nullptr), unflushed_input(0),
metadata(nullptr) metadata(nullptr)
{ {

View File

@ -43,7 +43,7 @@ class SlesOutput {
static constexpr unsigned N_BUFFERS = 3; static constexpr unsigned N_BUFFERS = 3;
static constexpr size_t BUFFER_SIZE = 65536; static constexpr size_t BUFFER_SIZE = 65536;
FilteredAudioOutput base; AudioOutput base;
SLES::Object engine_object, mix_object, play_object; SLES::Object engine_object, mix_object, play_object;
SLES::Play play; SLES::Play play;
@ -87,9 +87,9 @@ class SlesOutput {
uint8_t buffers[N_BUFFERS][BUFFER_SIZE]; uint8_t buffers[N_BUFFERS][BUFFER_SIZE];
public: public:
SlesOutput(const ConfigBlock &block); SlesOutput();
operator FilteredAudioOutput *() { operator AudioOutput *() {
return &base; return &base;
} }
@ -129,8 +129,8 @@ private:
static constexpr Domain sles_domain("sles"); static constexpr Domain sles_domain("sles");
SlesOutput::SlesOutput(const ConfigBlock &block) SlesOutput::SlesOutput()
:base(sles_output_plugin, block) :base(sles_output_plugin)
{ {
} }
@ -416,9 +416,9 @@ sles_test_default_device()
} }
inline SlesOutput * inline SlesOutput *
SlesOutput::Create(EventLoop &, const ConfigBlock &block) SlesOutput::Create(EventLoop &, const ConfigBlock &)
{ {
return new SlesOutput(block); return new SlesOutput();
} }
typedef AudioOutputWrapper<SlesOutput> Wrapper; typedef AudioOutputWrapper<SlesOutput> Wrapper;

View File

@ -18,19 +18,17 @@
*/ */
#include "config.h" #include "config.h"
#include "output/Filtered.hxx" #include "output/Interface.hxx"
#include "output/Registry.hxx"
#include "output/OutputPlugin.hxx" #include "output/OutputPlugin.hxx"
#include "config/Param.hxx" #include "config/Param.hxx"
#include "config/ConfigGlobal.hxx" #include "config/ConfigGlobal.hxx"
#include "config/ConfigOption.hxx" #include "config/ConfigOption.hxx"
#include "Idle.hxx" #include "config/Block.hxx"
#include "Main.hxx"
#include "event/Thread.hxx" #include "event/Thread.hxx"
#include "fs/Path.hxx" #include "fs/Path.hxx"
#include "AudioParser.hxx" #include "AudioParser.hxx"
#include "ReplayGainConfig.hxx"
#include "pcm/PcmConvert.hxx" #include "pcm/PcmConvert.hxx"
#include "filter/FilterRegistry.hxx"
#include "util/StringBuffer.hxx" #include "util/StringBuffer.hxx"
#include "util/RuntimeError.hxx" #include "util/RuntimeError.hxx"
#include "util/ScopeExit.hxx" #include "util/ScopeExit.hxx"
@ -42,28 +40,29 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
const FilterPlugin * static AudioOutput *
filter_plugin_by_name(gcc_unused const char *name) noexcept
{
assert(false);
return NULL;
}
static FilteredAudioOutput *
load_audio_output(EventLoop &event_loop, const char *name) load_audio_output(EventLoop &event_loop, const char *name)
{ {
const auto *param = config_find_block(ConfigBlockOption::AUDIO_OUTPUT, const auto *block = config_find_block(ConfigBlockOption::AUDIO_OUTPUT,
"name", name); "name", name);
if (param == NULL) if (block == nullptr)
throw FormatRuntimeError("No such configured audio output: %s\n", throw FormatRuntimeError("No such configured audio output: %s",
name); name);
return audio_output_new(event_loop, ReplayGainConfig(), *param, const char *plugin_name = block->GetBlockValue("type");
*(MixerListener *)nullptr); if (plugin_name == nullptr)
throw std::runtime_error("Missing \"type\" configuration");
const auto *plugin = AudioOutputPlugin_get(plugin_name);
if (plugin == nullptr)
throw FormatRuntimeError("No such audio output plugin: %s",
plugin_name);
return ao_plugin_init(event_loop, *plugin, *block);
} }
static void static void
run_output(FilteredAudioOutput &ao, AudioFormat audio_format) run_output(AudioOutput &ao, AudioFormat audio_format)
{ {
/* open the audio output */ /* open the audio output */
@ -140,8 +139,7 @@ try {
/* cleanup and exit */ /* cleanup and exit */
ao->BeginDestroy(); ao_plugin_finish(ao);
ao->FinishDestroy();
config_global_finish(); config_global_finish();