output/Wrapper: new helper class
This commit is contained in:
parent
977834179a
commit
0b9f650fe2
@ -1236,6 +1236,7 @@ OUTPUT_LIBS = \
|
||||
OUTPUT_API_SRC = \
|
||||
src/output/OutputAPI.hxx \
|
||||
src/output/Internal.hxx \
|
||||
src/output/Wrapper.hxx \
|
||||
src/output/Registry.cxx src/output/Registry.hxx \
|
||||
src/output/MultipleOutputs.cxx src/output/MultipleOutputs.hxx \
|
||||
src/output/OutputThread.cxx \
|
||||
|
93
src/output/Wrapper.hxx
Normal file
93
src/output/Wrapper.hxx
Normal 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 ¶m, 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
|
@ -20,6 +20,7 @@
|
||||
#include "config.h"
|
||||
#include "JackOutputPlugin.hxx"
|
||||
#include "../OutputAPI.hxx"
|
||||
#include "../Wrapper.hxx"
|
||||
#include "config/ConfigError.hxx"
|
||||
#include "util/ConstBuffer.hxx"
|
||||
#include "util/SplitString.hxx"
|
||||
@ -100,6 +101,10 @@ struct JackOutput {
|
||||
|
||||
bool Open(AudioFormat &new_audio_format, Error &error);
|
||||
|
||||
void Close() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
bool Start(Error &error);
|
||||
void Stop();
|
||||
|
||||
@ -117,7 +122,15 @@ struct JackOutput {
|
||||
*/
|
||||
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);
|
||||
|
||||
bool Pause();
|
||||
};
|
||||
|
||||
static constexpr Domain jack_output_domain("jack_output");
|
||||
@ -468,30 +481,6 @@ mpd_jack_init(const config_param ¶m, Error &error)
|
||||
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.
|
||||
*/
|
||||
@ -648,33 +637,6 @@ JackOutput::Open(AudioFormat &new_audio_format, Error &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
|
||||
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
|
||||
mpd_jack_play(AudioOutput *ao, const void *chunk, size_t size,
|
||||
Error &error)
|
||||
inline bool
|
||||
JackOutput::Pause()
|
||||
{
|
||||
JackOutput &jo = *(JackOutput *)ao;
|
||||
|
||||
return jo.Play(chunk, size, error);
|
||||
}
|
||||
|
||||
static bool
|
||||
mpd_jack_pause(AudioOutput *ao)
|
||||
{
|
||||
JackOutput *jd = (JackOutput *)ao;
|
||||
|
||||
if (jd->shutdown)
|
||||
if (shutdown)
|
||||
return false;
|
||||
|
||||
jd->pause = true;
|
||||
pause = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef AudioOutputWrapper<JackOutput> Wrapper;
|
||||
|
||||
const struct AudioOutputPlugin jack_output_plugin = {
|
||||
"jack",
|
||||
mpd_jack_test_default_device,
|
||||
mpd_jack_init,
|
||||
mpd_jack_finish,
|
||||
mpd_jack_enable,
|
||||
mpd_jack_disable,
|
||||
mpd_jack_open,
|
||||
mpd_jack_close,
|
||||
mpd_jack_delay,
|
||||
&Wrapper::Finish,
|
||||
&Wrapper::Enable,
|
||||
&Wrapper::Disable,
|
||||
&Wrapper::Open,
|
||||
&Wrapper::Close,
|
||||
&Wrapper::Delay,
|
||||
nullptr,
|
||||
mpd_jack_play,
|
||||
&Wrapper::Play,
|
||||
nullptr,
|
||||
nullptr,
|
||||
mpd_jack_pause,
|
||||
&Wrapper::Pause,
|
||||
nullptr,
|
||||
};
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "config.h"
|
||||
#include "PipeOutputPlugin.hxx"
|
||||
#include "../OutputAPI.hxx"
|
||||
#include "../Wrapper.hxx"
|
||||
#include "config/ConfigError.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
@ -29,6 +30,8 @@
|
||||
#include <stdio.h>
|
||||
|
||||
class PipeOutput {
|
||||
friend AudioOutputWrapper<PipeOutput>;
|
||||
|
||||
AudioOutput base;
|
||||
|
||||
std::string cmd;
|
||||
@ -40,7 +43,7 @@ class PipeOutput {
|
||||
bool Configure(const config_param ¶m, Error &error);
|
||||
|
||||
public:
|
||||
static AudioOutput *Create(const config_param ¶m, Error &error);
|
||||
static PipeOutput *Create(const config_param ¶m, Error &error);
|
||||
|
||||
bool Open(AudioFormat &audio_format, Error &error);
|
||||
|
||||
@ -70,7 +73,7 @@ PipeOutput::Configure(const config_param ¶m, Error &error)
|
||||
return true;
|
||||
}
|
||||
|
||||
inline AudioOutput *
|
||||
inline PipeOutput *
|
||||
PipeOutput::Create(const config_param ¶m, Error &error)
|
||||
{
|
||||
PipeOutput *po = new PipeOutput();
|
||||
@ -80,21 +83,7 @@ PipeOutput::Create(const config_param ¶m, Error &error)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &po->base;
|
||||
}
|
||||
|
||||
static AudioOutput *
|
||||
pipe_output_init(const config_param ¶m, Error &error)
|
||||
{
|
||||
return PipeOutput::Create(param, error);
|
||||
}
|
||||
|
||||
static void
|
||||
pipe_output_finish(AudioOutput *ao)
|
||||
{
|
||||
PipeOutput *pd = (PipeOutput *)ao;
|
||||
|
||||
delete pd;
|
||||
return po;
|
||||
}
|
||||
|
||||
inline bool
|
||||
@ -110,22 +99,6 @@ PipeOutput::Open(gcc_unused AudioFormat &audio_format, Error &error)
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
static size_t
|
||||
pipe_output_play(AudioOutput *ao, const void *chunk, size_t size,
|
||||
Error &error)
|
||||
{
|
||||
PipeOutput &po = *(PipeOutput *)ao;
|
||||
|
||||
return po.Play(chunk, size, error);
|
||||
}
|
||||
typedef AudioOutputWrapper<PipeOutput> Wrapper;
|
||||
|
||||
const struct AudioOutputPlugin pipe_output_plugin = {
|
||||
"pipe",
|
||||
nullptr,
|
||||
pipe_output_init,
|
||||
pipe_output_finish,
|
||||
&Wrapper::Init,
|
||||
&Wrapper::Finish,
|
||||
nullptr,
|
||||
nullptr,
|
||||
pipe_output_open,
|
||||
pipe_output_close,
|
||||
&Wrapper::Open,
|
||||
&Wrapper::Close,
|
||||
nullptr,
|
||||
nullptr,
|
||||
pipe_output_play,
|
||||
&Wrapper::Play,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "config.h"
|
||||
#include "RecorderOutputPlugin.hxx"
|
||||
#include "../OutputAPI.hxx"
|
||||
#include "../Wrapper.hxx"
|
||||
#include "encoder/EncoderPlugin.hxx"
|
||||
#include "encoder/EncoderList.hxx"
|
||||
#include "config/ConfigError.hxx"
|
||||
@ -213,16 +214,6 @@ RecorderOutput::Open(AudioFormat &audio_format, Error &error)
|
||||
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
|
||||
RecorderOutput::Close()
|
||||
{
|
||||
@ -238,14 +229,6 @@ RecorderOutput::Close()
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void
|
||||
recorder_output_close(AudioOutput *ao)
|
||||
{
|
||||
RecorderOutput &recorder = *(RecorderOutput *)ao;
|
||||
|
||||
recorder.Close();
|
||||
}
|
||||
|
||||
inline void
|
||||
RecorderOutput::SendTag(const Tag &tag)
|
||||
{
|
||||
@ -275,6 +258,8 @@ recorder_output_play(AudioOutput *ao, const void *chunk, size_t size,
|
||||
? size : 0;
|
||||
}
|
||||
|
||||
typedef AudioOutputWrapper<RecorderOutput> Wrapper;
|
||||
|
||||
const struct AudioOutputPlugin recorder_output_plugin = {
|
||||
"recorder",
|
||||
nullptr,
|
||||
@ -282,8 +267,8 @@ const struct AudioOutputPlugin recorder_output_plugin = {
|
||||
recorder_output_finish,
|
||||
nullptr,
|
||||
nullptr,
|
||||
recorder_output_open,
|
||||
recorder_output_close,
|
||||
&Wrapper::Open,
|
||||
&Wrapper::Close,
|
||||
nullptr,
|
||||
recorder_output_send_tag,
|
||||
recorder_output_play,
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "config.h"
|
||||
#include "RoarOutputPlugin.hxx"
|
||||
#include "../OutputAPI.hxx"
|
||||
#include "../Wrapper.hxx"
|
||||
#include "mixer/MixerList.hxx"
|
||||
#include "thread/Mutex.hxx"
|
||||
#include "util/Error.hxx"
|
||||
@ -36,6 +37,8 @@
|
||||
#undef new
|
||||
|
||||
class RoarOutput {
|
||||
friend struct AudioOutputWrapper<RoarOutput>;
|
||||
|
||||
AudioOutput base;
|
||||
|
||||
std::string host, name;
|
||||
@ -146,14 +149,6 @@ roar_init(const config_param ¶m, Error &error)
|
||||
return *self;
|
||||
}
|
||||
|
||||
static void
|
||||
roar_finish(AudioOutput *ao)
|
||||
{
|
||||
RoarOutput *self = (RoarOutput *)ao;
|
||||
|
||||
delete self;
|
||||
}
|
||||
|
||||
static void
|
||||
roar_use_audio_format(struct roar_audio_info *info,
|
||||
AudioFormat &audio_format)
|
||||
@ -221,14 +216,6 @@ RoarOutput::Open(AudioFormat &audio_format, Error &error)
|
||||
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
|
||||
RoarOutput::Close()
|
||||
{
|
||||
@ -242,13 +229,6 @@ RoarOutput::Close()
|
||||
roar_disconnect(&con);
|
||||
}
|
||||
|
||||
static void
|
||||
roar_close(AudioOutput *ao)
|
||||
{
|
||||
RoarOutput *self = (RoarOutput *)ao;
|
||||
self->Close();
|
||||
}
|
||||
|
||||
inline void
|
||||
RoarOutput::Cancel()
|
||||
{
|
||||
@ -277,14 +257,6 @@ RoarOutput::Cancel()
|
||||
alive = true;
|
||||
}
|
||||
|
||||
static void
|
||||
roar_cancel(AudioOutput *ao)
|
||||
{
|
||||
RoarOutput *self = (RoarOutput *)ao;
|
||||
|
||||
self->Cancel();
|
||||
}
|
||||
|
||||
inline size_t
|
||||
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;
|
||||
}
|
||||
|
||||
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*
|
||||
roar_tag_convert(TagType type, bool *is_uuid)
|
||||
{
|
||||
@ -413,20 +377,22 @@ roar_send_tag(AudioOutput *ao, const Tag &meta)
|
||||
self->SendTag(meta);
|
||||
}
|
||||
|
||||
typedef AudioOutputWrapper<RoarOutput> Wrapper;
|
||||
|
||||
const struct AudioOutputPlugin roar_output_plugin = {
|
||||
"roar",
|
||||
nullptr,
|
||||
roar_init,
|
||||
roar_finish,
|
||||
&Wrapper::Finish,
|
||||
nullptr,
|
||||
nullptr,
|
||||
roar_open,
|
||||
roar_close,
|
||||
&Wrapper::Open,
|
||||
&Wrapper::Close,
|
||||
nullptr,
|
||||
roar_send_tag,
|
||||
roar_play,
|
||||
&Wrapper::Play,
|
||||
nullptr,
|
||||
roar_cancel,
|
||||
&Wrapper::Cancel,
|
||||
nullptr,
|
||||
&roar_mixer_plugin,
|
||||
};
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "Play.hxx"
|
||||
#include "AndroidSimpleBufferQueue.hxx"
|
||||
#include "../../OutputAPI.hxx"
|
||||
#include "../../Wrapper.hxx"
|
||||
#include "util/Macros.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
@ -34,6 +35,8 @@
|
||||
#include <SLES/OpenSLES_Android.h>
|
||||
|
||||
class SlesOutput {
|
||||
friend AudioOutputWrapper<SlesOutput>;
|
||||
|
||||
static constexpr unsigned N_BUFFERS = 3;
|
||||
static constexpr size_t BUFFER_SIZE = 65536;
|
||||
|
||||
@ -455,85 +458,22 @@ sles_output_init(const config_param ¶m, Error &error)
|
||||
return *sles;
|
||||
}
|
||||
|
||||
static void
|
||||
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();
|
||||
}
|
||||
typedef AudioOutputWrapper<SlesOutput> Wrapper;
|
||||
|
||||
const struct AudioOutputPlugin sles_output_plugin = {
|
||||
"sles",
|
||||
sles_test_default_device,
|
||||
sles_output_init,
|
||||
sles_output_finish,
|
||||
&Wrapper::Finish,
|
||||
nullptr,
|
||||
nullptr,
|
||||
sles_output_open,
|
||||
sles_output_close,
|
||||
sles_output_delay,
|
||||
&Wrapper::Open,
|
||||
&Wrapper::Close,
|
||||
&Wrapper::Delay,
|
||||
nullptr,
|
||||
sles_output_play,
|
||||
sles_output_drain,
|
||||
sles_output_cancel,
|
||||
sles_output_pause,
|
||||
&Wrapper::Play,
|
||||
&Wrapper::Drain,
|
||||
&Wrapper::Cancel,
|
||||
&Wrapper::Pause,
|
||||
nullptr,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user