output/Wrapper: new helper class

This commit is contained in:
Max Kellermann 2014-12-29 23:45:14 +01:00
parent 977834179a
commit 0b9f650fe2
7 changed files with 160 additions and 256 deletions

View File

@ -1236,6 +1236,7 @@ OUTPUT_LIBS = \
OUTPUT_API_SRC = \ OUTPUT_API_SRC = \
src/output/OutputAPI.hxx \ src/output/OutputAPI.hxx \
src/output/Internal.hxx \ src/output/Internal.hxx \
src/output/Wrapper.hxx \
src/output/Registry.cxx src/output/Registry.hxx \ src/output/Registry.cxx src/output/Registry.hxx \
src/output/MultipleOutputs.cxx src/output/MultipleOutputs.hxx \ src/output/MultipleOutputs.cxx src/output/MultipleOutputs.hxx \
src/output/OutputThread.cxx \ src/output/OutputThread.cxx \

93
src/output/Wrapper.hxx Normal file
View File

@ -0,0 +1,93 @@
/*
* 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_OUTPUT_WRAPPER_HXX
#define MPD_OUTPUT_WRAPPER_HXX
#include "util/Cast.hxx"
template<class T>
struct AudioOutputWrapper {
static T &Cast(AudioOutput &ao) {
return ContainerCast(ao, &T::base);
}
static AudioOutput *Init(const config_param &param, Error &error) {
T *t = T::Create(param, error);
return t != nullptr
? &t->base
: nullptr;
}
static void Finish(AudioOutput *ao) {
T *t = &Cast(*ao);
delete t;
}
static bool Enable(AudioOutput *ao, Error &error) {
T &t = Cast(*ao);
return t.Enable(error);
}
static void Disable(AudioOutput *ao) {
T &t = Cast(*ao);
t.Disable();
}
static bool Open(AudioOutput *ao, AudioFormat &audio_format,
Error &error) {
T &t = Cast(*ao);
return t.Open(audio_format, error);
}
static void Close(AudioOutput *ao) {
T &t = Cast(*ao);
t.Close();
}
gcc_pure
static unsigned Delay(AudioOutput *ao) {
T &t = Cast(*ao);
return t.Delay();
}
static size_t Play(AudioOutput *ao, const void *chunk, size_t size,
Error &error) {
T &t = Cast(*ao);
return t.Play(chunk, size, error);
}
static void Drain(AudioOutput *ao) {
T &t = Cast(*ao);
t.Drain();
}
static void Cancel(AudioOutput *ao) {
T &t = Cast(*ao);
t.Cancel();
}
gcc_pure
static bool Pause(AudioOutput *ao) {
T &t = Cast(*ao);
return t.Pause();
}
};
#endif

View File

@ -20,6 +20,7 @@
#include "config.h" #include "config.h"
#include "JackOutputPlugin.hxx" #include "JackOutputPlugin.hxx"
#include "../OutputAPI.hxx" #include "../OutputAPI.hxx"
#include "../Wrapper.hxx"
#include "config/ConfigError.hxx" #include "config/ConfigError.hxx"
#include "util/ConstBuffer.hxx" #include "util/ConstBuffer.hxx"
#include "util/SplitString.hxx" #include "util/SplitString.hxx"
@ -100,6 +101,10 @@ struct JackOutput {
bool Open(AudioFormat &new_audio_format, Error &error); bool Open(AudioFormat &new_audio_format, Error &error);
void Close() {
Stop();
}
bool Start(Error &error); bool Start(Error &error);
void Stop(); void Stop();
@ -117,7 +122,15 @@ struct JackOutput {
*/ */
size_t WriteSamples(const float *src, size_t n_frames); size_t WriteSamples(const float *src, size_t n_frames);
unsigned Delay() const {
return base.pause && pause && !shutdown
? 1000
: 0;
}
size_t Play(const void *chunk, size_t size, Error &error); size_t Play(const void *chunk, size_t size, Error &error);
bool Pause();
}; };
static constexpr Domain jack_output_domain("jack_output"); static constexpr Domain jack_output_domain("jack_output");
@ -468,30 +481,6 @@ mpd_jack_init(const config_param &param, Error &error)
return &jd->base; return &jd->base;
} }
static void
mpd_jack_finish(AudioOutput *ao)
{
JackOutput *jd = (JackOutput *)ao;
delete jd;
}
static bool
mpd_jack_enable(AudioOutput *ao, Error &error)
{
JackOutput &jo = *(JackOutput *)ao;
return jo.Enable(error);
}
static void
mpd_jack_disable(AudioOutput *ao)
{
JackOutput &jo = *(JackOutput *)ao;
jo.Disable();
}
/** /**
* Stops the playback on the JACK connection. * Stops the playback on the JACK connection.
*/ */
@ -648,33 +637,6 @@ JackOutput::Open(AudioFormat &new_audio_format, Error &error)
return Start(error); return Start(error);
} }
static bool
mpd_jack_open(AudioOutput *ao, AudioFormat &audio_format,
Error &error)
{
JackOutput &jo = *(JackOutput *)ao;
return jo.Open(audio_format, error);
}
static void
mpd_jack_close(AudioOutput *ao)
{
JackOutput &jo = *(JackOutput *)ao;
jo.Stop();
}
static unsigned
mpd_jack_delay(AudioOutput *ao)
{
JackOutput *jd = (JackOutput *)ao;
return jd->base.pause && jd->pause && !jd->shutdown
? 1000
: 0;
}
inline size_t inline size_t
JackOutput::WriteSamples(const float *src, size_t n_frames) JackOutput::WriteSamples(const float *src, size_t n_frames)
{ {
@ -744,42 +706,33 @@ JackOutput::Play(const void *chunk, size_t size, Error &error)
} }
} }
static size_t inline bool
mpd_jack_play(AudioOutput *ao, const void *chunk, size_t size, JackOutput::Pause()
Error &error)
{ {
JackOutput &jo = *(JackOutput *)ao; if (shutdown)
return jo.Play(chunk, size, error);
}
static bool
mpd_jack_pause(AudioOutput *ao)
{
JackOutput *jd = (JackOutput *)ao;
if (jd->shutdown)
return false; return false;
jd->pause = true; pause = true;
return true; return true;
} }
typedef AudioOutputWrapper<JackOutput> Wrapper;
const struct AudioOutputPlugin jack_output_plugin = { const struct AudioOutputPlugin jack_output_plugin = {
"jack", "jack",
mpd_jack_test_default_device, mpd_jack_test_default_device,
mpd_jack_init, mpd_jack_init,
mpd_jack_finish, &Wrapper::Finish,
mpd_jack_enable, &Wrapper::Enable,
mpd_jack_disable, &Wrapper::Disable,
mpd_jack_open, &Wrapper::Open,
mpd_jack_close, &Wrapper::Close,
mpd_jack_delay, &Wrapper::Delay,
nullptr, nullptr,
mpd_jack_play, &Wrapper::Play,
nullptr, nullptr,
nullptr, nullptr,
mpd_jack_pause, &Wrapper::Pause,
nullptr, nullptr,
}; };

View File

@ -20,6 +20,7 @@
#include "config.h" #include "config.h"
#include "PipeOutputPlugin.hxx" #include "PipeOutputPlugin.hxx"
#include "../OutputAPI.hxx" #include "../OutputAPI.hxx"
#include "../Wrapper.hxx"
#include "config/ConfigError.hxx" #include "config/ConfigError.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
@ -29,6 +30,8 @@
#include <stdio.h> #include <stdio.h>
class PipeOutput { class PipeOutput {
friend AudioOutputWrapper<PipeOutput>;
AudioOutput base; AudioOutput base;
std::string cmd; std::string cmd;
@ -40,7 +43,7 @@ class PipeOutput {
bool Configure(const config_param &param, Error &error); bool Configure(const config_param &param, Error &error);
public: public:
static AudioOutput *Create(const config_param &param, Error &error); static PipeOutput *Create(const config_param &param, Error &error);
bool Open(AudioFormat &audio_format, Error &error); bool Open(AudioFormat &audio_format, Error &error);
@ -70,7 +73,7 @@ PipeOutput::Configure(const config_param &param, Error &error)
return true; return true;
} }
inline AudioOutput * inline PipeOutput *
PipeOutput::Create(const config_param &param, Error &error) PipeOutput::Create(const config_param &param, Error &error)
{ {
PipeOutput *po = new PipeOutput(); PipeOutput *po = new PipeOutput();
@ -80,21 +83,7 @@ PipeOutput::Create(const config_param &param, Error &error)
return nullptr; return nullptr;
} }
return &po->base; return po;
}
static AudioOutput *
pipe_output_init(const config_param &param, Error &error)
{
return PipeOutput::Create(param, error);
}
static void
pipe_output_finish(AudioOutput *ao)
{
PipeOutput *pd = (PipeOutput *)ao;
delete pd;
} }
inline bool inline bool
@ -110,22 +99,6 @@ PipeOutput::Open(gcc_unused AudioFormat &audio_format, Error &error)
return true; return true;
} }
static bool
pipe_output_open(AudioOutput *ao, AudioFormat &audio_format, Error &error)
{
PipeOutput &po = *(PipeOutput *)ao;
return po.Open(audio_format, error);
}
static void
pipe_output_close(AudioOutput *ao)
{
PipeOutput &po = *(PipeOutput *)ao;
po.Close();
}
inline size_t inline size_t
PipeOutput::Play(const void *chunk, size_t size, Error &error) PipeOutput::Play(const void *chunk, size_t size, Error &error)
{ {
@ -136,27 +109,20 @@ PipeOutput::Play(const void *chunk, size_t size, Error &error)
return nbytes; return nbytes;
} }
static size_t typedef AudioOutputWrapper<PipeOutput> Wrapper;
pipe_output_play(AudioOutput *ao, const void *chunk, size_t size,
Error &error)
{
PipeOutput &po = *(PipeOutput *)ao;
return po.Play(chunk, size, error);
}
const struct AudioOutputPlugin pipe_output_plugin = { const struct AudioOutputPlugin pipe_output_plugin = {
"pipe", "pipe",
nullptr, nullptr,
pipe_output_init, &Wrapper::Init,
pipe_output_finish, &Wrapper::Finish,
nullptr, nullptr,
nullptr, nullptr,
pipe_output_open, &Wrapper::Open,
pipe_output_close, &Wrapper::Close,
nullptr, nullptr,
nullptr, nullptr,
pipe_output_play, &Wrapper::Play,
nullptr, nullptr,
nullptr, nullptr,
nullptr, nullptr,

View File

@ -20,6 +20,7 @@
#include "config.h" #include "config.h"
#include "RecorderOutputPlugin.hxx" #include "RecorderOutputPlugin.hxx"
#include "../OutputAPI.hxx" #include "../OutputAPI.hxx"
#include "../Wrapper.hxx"
#include "encoder/EncoderPlugin.hxx" #include "encoder/EncoderPlugin.hxx"
#include "encoder/EncoderList.hxx" #include "encoder/EncoderList.hxx"
#include "config/ConfigError.hxx" #include "config/ConfigError.hxx"
@ -213,16 +214,6 @@ RecorderOutput::Open(AudioFormat &audio_format, Error &error)
return true; return true;
} }
static bool
recorder_output_open(AudioOutput *ao,
AudioFormat &audio_format,
Error &error)
{
RecorderOutput &recorder = *(RecorderOutput *)ao;
return recorder.Open(audio_format, error);
}
inline void inline void
RecorderOutput::Close() RecorderOutput::Close()
{ {
@ -238,14 +229,6 @@ RecorderOutput::Close()
close(fd); close(fd);
} }
static void
recorder_output_close(AudioOutput *ao)
{
RecorderOutput &recorder = *(RecorderOutput *)ao;
recorder.Close();
}
inline void inline void
RecorderOutput::SendTag(const Tag &tag) RecorderOutput::SendTag(const Tag &tag)
{ {
@ -275,6 +258,8 @@ recorder_output_play(AudioOutput *ao, const void *chunk, size_t size,
? size : 0; ? size : 0;
} }
typedef AudioOutputWrapper<RecorderOutput> Wrapper;
const struct AudioOutputPlugin recorder_output_plugin = { const struct AudioOutputPlugin recorder_output_plugin = {
"recorder", "recorder",
nullptr, nullptr,
@ -282,8 +267,8 @@ const struct AudioOutputPlugin recorder_output_plugin = {
recorder_output_finish, recorder_output_finish,
nullptr, nullptr,
nullptr, nullptr,
recorder_output_open, &Wrapper::Open,
recorder_output_close, &Wrapper::Close,
nullptr, nullptr,
recorder_output_send_tag, recorder_output_send_tag,
recorder_output_play, recorder_output_play,

View File

@ -21,6 +21,7 @@
#include "config.h" #include "config.h"
#include "RoarOutputPlugin.hxx" #include "RoarOutputPlugin.hxx"
#include "../OutputAPI.hxx" #include "../OutputAPI.hxx"
#include "../Wrapper.hxx"
#include "mixer/MixerList.hxx" #include "mixer/MixerList.hxx"
#include "thread/Mutex.hxx" #include "thread/Mutex.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
@ -36,6 +37,8 @@
#undef new #undef new
class RoarOutput { class RoarOutput {
friend struct AudioOutputWrapper<RoarOutput>;
AudioOutput base; AudioOutput base;
std::string host, name; std::string host, name;
@ -146,14 +149,6 @@ roar_init(const config_param &param, Error &error)
return *self; return *self;
} }
static void
roar_finish(AudioOutput *ao)
{
RoarOutput *self = (RoarOutput *)ao;
delete self;
}
static void static void
roar_use_audio_format(struct roar_audio_info *info, roar_use_audio_format(struct roar_audio_info *info,
AudioFormat &audio_format) AudioFormat &audio_format)
@ -221,14 +216,6 @@ RoarOutput::Open(AudioFormat &audio_format, Error &error)
return true; return true;
} }
static bool
roar_open(AudioOutput *ao, AudioFormat &audio_format, Error &error)
{
RoarOutput *self = (RoarOutput *)ao;
return self->Open(audio_format, error);
}
inline void inline void
RoarOutput::Close() RoarOutput::Close()
{ {
@ -242,13 +229,6 @@ RoarOutput::Close()
roar_disconnect(&con); roar_disconnect(&con);
} }
static void
roar_close(AudioOutput *ao)
{
RoarOutput *self = (RoarOutput *)ao;
self->Close();
}
inline void inline void
RoarOutput::Cancel() RoarOutput::Cancel()
{ {
@ -277,14 +257,6 @@ RoarOutput::Cancel()
alive = true; alive = true;
} }
static void
roar_cancel(AudioOutput *ao)
{
RoarOutput *self = (RoarOutput *)ao;
self->Cancel();
}
inline size_t inline size_t
RoarOutput::Play(const void *chunk, size_t size, Error &error) RoarOutput::Play(const void *chunk, size_t size, Error &error)
{ {
@ -302,14 +274,6 @@ RoarOutput::Play(const void *chunk, size_t size, Error &error)
return nbytes; return nbytes;
} }
static size_t
roar_play(AudioOutput *ao, const void *chunk, size_t size,
Error &error)
{
RoarOutput *self = (RoarOutput *)ao;
return self->Play(chunk, size, error);
}
static const char* static const char*
roar_tag_convert(TagType type, bool *is_uuid) roar_tag_convert(TagType type, bool *is_uuid)
{ {
@ -413,20 +377,22 @@ roar_send_tag(AudioOutput *ao, const Tag &meta)
self->SendTag(meta); self->SendTag(meta);
} }
typedef AudioOutputWrapper<RoarOutput> Wrapper;
const struct AudioOutputPlugin roar_output_plugin = { const struct AudioOutputPlugin roar_output_plugin = {
"roar", "roar",
nullptr, nullptr,
roar_init, roar_init,
roar_finish, &Wrapper::Finish,
nullptr, nullptr,
nullptr, nullptr,
roar_open, &Wrapper::Open,
roar_close, &Wrapper::Close,
nullptr, nullptr,
roar_send_tag, roar_send_tag,
roar_play, &Wrapper::Play,
nullptr, nullptr,
roar_cancel, &Wrapper::Cancel,
nullptr, nullptr,
&roar_mixer_plugin, &roar_mixer_plugin,
}; };

View File

@ -24,6 +24,7 @@
#include "Play.hxx" #include "Play.hxx"
#include "AndroidSimpleBufferQueue.hxx" #include "AndroidSimpleBufferQueue.hxx"
#include "../../OutputAPI.hxx" #include "../../OutputAPI.hxx"
#include "../../Wrapper.hxx"
#include "util/Macros.hxx" #include "util/Macros.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
@ -34,6 +35,8 @@
#include <SLES/OpenSLES_Android.h> #include <SLES/OpenSLES_Android.h>
class SlesOutput { class SlesOutput {
friend AudioOutputWrapper<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;
@ -455,85 +458,22 @@ sles_output_init(const config_param &param, Error &error)
return *sles; return *sles;
} }
static void typedef AudioOutputWrapper<SlesOutput> Wrapper;
sles_output_finish(AudioOutput *ao)
{
SlesOutput *sles = (SlesOutput *)ao;
delete sles;
}
static bool
sles_output_open(AudioOutput *ao, AudioFormat &audio_format, Error &error)
{
SlesOutput &sles = *(SlesOutput *)ao;
return sles.Open(audio_format, error);
}
static void
sles_output_close(AudioOutput *ao)
{
SlesOutput &sles = *(SlesOutput *)ao;
sles.Close();
}
static unsigned
sles_output_delay(AudioOutput *ao)
{
SlesOutput &sles = *(SlesOutput *)ao;
return sles.Delay();
}
static size_t
sles_output_play(AudioOutput *ao, const void *chunk, size_t size,
Error &error)
{
SlesOutput &sles = *(SlesOutput *)ao;
return sles.Play(chunk, size, error);
}
static void
sles_output_drain(AudioOutput *ao)
{
SlesOutput &sles = *(SlesOutput *)ao;
sles.Drain();
}
static void
sles_output_cancel(AudioOutput *ao)
{
SlesOutput &sles = *(SlesOutput *)ao;
sles.Cancel();
}
static bool
sles_output_pause(AudioOutput *ao)
{
SlesOutput &sles = *(SlesOutput *)ao;
return sles.Pause();
}
const struct AudioOutputPlugin sles_output_plugin = { const struct AudioOutputPlugin sles_output_plugin = {
"sles", "sles",
sles_test_default_device, sles_test_default_device,
sles_output_init, sles_output_init,
sles_output_finish, &Wrapper::Finish,
nullptr, nullptr,
nullptr, nullptr,
sles_output_open, &Wrapper::Open,
sles_output_close, &Wrapper::Close,
sles_output_delay, &Wrapper::Delay,
nullptr, nullptr,
sles_output_play, &Wrapper::Play,
sles_output_drain, &Wrapper::Drain,
sles_output_cancel, &Wrapper::Cancel,
sles_output_pause, &Wrapper::Pause,
nullptr, nullptr,
}; };