Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
mpd
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Иван Мажукин
mpd
Commits
31bad5f7
Commit
31bad5f7
authored
Aug 09, 2017
by
Max Kellermann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
output/Interface: convert to abstract class
Yet another C-style vtable replaced with C++.
parent
1cf7f3d8
Hide whitespace changes
Inline
Side-by-side
Showing
30 changed files
with
528 additions
and
1127 deletions
+528
-1127
Makefile.am
Makefile.am
+0
-1
Filtered.cxx
src/output/Filtered.cxx
+13
-16
Filtered.hxx
src/output/Filtered.hxx
+8
-2
Finish.cxx
src/output/Finish.cxx
+2
-4
Init.cxx
src/output/Init.cxx
+10
-21
Interface.hxx
src/output/Interface.hxx
+101
-9
OutputPlugin.cxx
src/output/OutputPlugin.cxx
+0
-74
OutputPlugin.hxx
src/output/OutputPlugin.hxx
+0
-119
Wrapper.hxx
src/output/Wrapper.hxx
+0
-101
AlsaOutputPlugin.cxx
src/output/plugins/AlsaOutputPlugin.cxx
+26
-49
AoOutputPlugin.cxx
src/output/plugins/AoOutputPlugin.cxx
+8
-26
FifoOutputPlugin.cxx
src/output/plugins/FifoOutputPlugin.cxx
+18
-39
HaikuOutputPlugin.cxx
src/output/plugins/HaikuOutputPlugin.cxx
+17
-34
JackOutputPlugin.cxx
src/output/plugins/JackOutputPlugin.cxx
+12
-29
NullOutputPlugin.cxx
src/output/plugins/NullOutputPlugin.cxx
+13
-34
OSXOutputPlugin.cxx
src/output/plugins/OSXOutputPlugin.cxx
+70
-90
OpenALOutputPlugin.cxx
src/output/plugins/OpenALOutputPlugin.cxx
+20
-40
OssOutputPlugin.cxx
src/output/plugins/OssOutputPlugin.cxx
+22
-40
PipeOutputPlugin.cxx
src/output/plugins/PipeOutputPlugin.cxx
+11
-32
PulseOutputPlugin.cxx
src/output/plugins/PulseOutputPlugin.cxx
+28
-51
RecorderOutputPlugin.cxx
src/output/plugins/RecorderOutputPlugin.cxx
+17
-38
RoarOutputPlugin.cxx
src/output/plugins/RoarOutputPlugin.cxx
+19
-40
ShoutOutputPlugin.cxx
src/output/plugins/ShoutOutputPlugin.cxx
+16
-32
SndioOutputPlugin.cxx
src/output/plugins/SndioOutputPlugin.cxx
+12
-32
SolarisOutputPlugin.cxx
src/output/plugins/SolarisOutputPlugin.cxx
+11
-28
WinmmOutputPlugin.cxx
src/output/plugins/WinmmOutputPlugin.cxx
+14
-31
HttpdInternal.hxx
src/output/plugins/httpd/HttpdInternal.hxx
+14
-21
HttpdOutputPlugin.cxx
src/output/plugins/httpd/HttpdOutputPlugin.cxx
+11
-30
SlesOutputPlugin.cxx
src/output/plugins/sles/SlesOutputPlugin.cxx
+23
-54
run_output.cxx
test/run_output.cxx
+12
-10
No files found.
Makefile.am
View file @
31bad5f7
...
...
@@ -1375,7 +1375,6 @@ OUTPUT_API_SRC = \
src/output/OutputAPI.hxx
\
src/output/Interface.hxx
\
src/output/Filtered.cxx src/output/Filtered.hxx
\
src/output/Wrapper.hxx
\
src/output/Registry.cxx src/output/Registry.hxx
\
src/output/MultipleOutputs.cxx src/output/MultipleOutputs.hxx
\
src/output/SharedPipeConsumer.cxx src/output/SharedPipeConsumer.hxx
\
...
...
src/output/Filtered.cxx
View file @
31bad5f7
...
...
@@ -20,7 +20,6 @@
#include "config.h"
#include "Filtered.hxx"
#include "Interface.hxx"
#include "OutputPlugin.hxx"
#include "Domain.hxx"
#include "Log.hxx"
#include "mixer/MixerInternal.hxx"
...
...
@@ -32,22 +31,20 @@
bool
FilteredAudioOutput
::
SupportsEnableDisable
()
const
noexcept
{
assert
((
output
->
GetPlugin
().
enable
==
nullptr
)
==
(
output
->
GetPlugin
().
disable
==
nullptr
));
return
output
->
GetPlugin
().
enable
!=
nullptr
;
return
output
->
SupportsEnableDisable
();
}
bool
FilteredAudioOutput
::
SupportsPause
()
const
noexcept
{
return
output
->
GetPlugin
().
pause
!=
nullptr
;
return
output
->
SupportsPause
()
;
}
void
FilteredAudioOutput
::
Enable
()
{
try
{
ao_plugin_enable
(
*
output
);
output
->
Enable
(
);
}
catch
(
const
std
::
runtime_error
&
e
)
{
std
::
throw_with_nested
(
FormatRuntimeError
(
"Failed to enable output %s"
,
GetLogName
()));
...
...
@@ -57,7 +54,7 @@ FilteredAudioOutput::Enable()
void
FilteredAudioOutput
::
Disable
()
noexcept
{
ao_plugin_disable
(
*
output
);
output
->
Disable
(
);
}
void
...
...
@@ -77,7 +74,7 @@ FilteredAudioOutput::OpenOutputAndConvert(AudioFormat desired_audio_format)
out_audio_format
=
desired_audio_format
;
try
{
ao_plugin_open
(
*
output
,
out_audio_format
);
output
->
Open
(
out_audio_format
);
}
catch
(
const
std
::
runtime_error
&
e
)
{
std
::
throw_with_nested
(
FormatRuntimeError
(
"Failed to open %s"
,
GetLogName
()));
...
...
@@ -91,7 +88,7 @@ FilteredAudioOutput::OpenOutputAndConvert(AudioFormat desired_audio_format)
try
{
ConfigureConvertFilter
();
}
catch
(
const
std
::
runtime_error
&
e
)
{
ao_plugin_close
(
*
output
);
output
->
Close
(
);
if
(
out_audio_format
.
format
==
SampleFormat
::
DSD
)
{
/* if the audio output supports DSD, but not
...
...
@@ -120,7 +117,7 @@ FilteredAudioOutput::CloseOutput(bool drain) noexcept
else
Cancel
();
ao_plugin_close
(
*
output
);
output
->
Close
(
);
}
void
...
...
@@ -149,31 +146,31 @@ FilteredAudioOutput::Close(bool drain) noexcept
std
::
chrono
::
steady_clock
::
duration
FilteredAudioOutput
::
Delay
()
noexcept
{
return
ao_plugin_delay
(
*
output
);
return
output
->
Delay
(
);
}
void
FilteredAudioOutput
::
SendTag
(
const
Tag
&
tag
)
{
ao_plugin_send_tag
(
*
output
,
tag
);
output
->
SendTag
(
tag
);
}
size_t
FilteredAudioOutput
::
Play
(
const
void
*
data
,
size_t
size
)
{
return
ao_plugin_play
(
*
output
,
data
,
size
);
return
output
->
Play
(
data
,
size
);
}
void
FilteredAudioOutput
::
Drain
()
{
ao_plugin_drain
(
*
output
);
output
->
Drain
(
);
}
void
FilteredAudioOutput
::
Cancel
()
noexcept
{
ao_plugin_cancel
(
*
output
);
output
->
Cancel
(
);
}
void
...
...
@@ -186,7 +183,7 @@ bool
FilteredAudioOutput
::
IteratePause
()
noexcept
{
try
{
return
ao_plugin_pause
(
*
output
);
return
output
->
Pause
(
);
}
catch
(
const
std
::
runtime_error
&
e
)
{
FormatError
(
e
,
"Failed to pause %s"
,
GetLogName
());
...
...
src/output/Filtered.hxx
View file @
31bad5f7
...
...
@@ -23,6 +23,7 @@
#include "AudioFormat.hxx"
#include "filter/Observer.hxx"
#include <memory>
#include <string>
#include <chrono>
...
...
@@ -31,6 +32,7 @@ class MusicPipe;
class
EventLoop
;
class
Mixer
;
class
MixerListener
;
struct
MixerPlugin
;
struct
MusicChunk
;
struct
ConfigBlock
;
class
AudioOutput
;
...
...
@@ -38,6 +40,8 @@ struct ReplayGainConfig;
struct
Tag
;
struct
FilteredAudioOutput
{
const
char
*
const
plugin_name
;
/**
* The device's configured display name.
*/
...
...
@@ -54,7 +58,7 @@ public:
/**
* The plugin which implements this output device.
*/
AudioOutput
*
const
output
;
std
::
unique_ptr
<
AudioOutput
>
output
;
/**
* The #mixer object associated with this audio output device.
...
...
@@ -120,7 +124,8 @@ public:
/**
* Throws #std::runtime_error on error.
*/
FilteredAudioOutput
(
AudioOutput
&
_output
,
FilteredAudioOutput
(
const
char
*
_plugin_name
,
std
::
unique_ptr
<
AudioOutput
>
&&
_output
,
const
ConfigBlock
&
block
);
~
FilteredAudioOutput
();
...
...
@@ -131,6 +136,7 @@ private:
public
:
void
Setup
(
EventLoop
&
event_loop
,
const
ReplayGainConfig
&
replay_gain_config
,
const
MixerPlugin
*
mixer_plugin
,
MixerListener
&
mixer_listener
,
const
ConfigBlock
&
block
);
...
...
src/output/Finish.cxx
View file @
31bad5f7
...
...
@@ -19,7 +19,7 @@
#include "config.h"
#include "Filtered.hxx"
#include "
OutputPlugin
.hxx"
#include "
Interface
.hxx"
#include "mixer/MixerControl.hxx"
#include "filter/FilterInternal.hxx"
...
...
@@ -31,8 +31,6 @@ FilteredAudioOutput::~FilteredAudioOutput()
delete
prepared_replay_gain_filter
;
delete
prepared_other_replay_gain_filter
;
delete
prepared_filter
;
ao_plugin_finish
(
output
);
}
void
...
...
@@ -45,5 +43,5 @@ FilteredAudioOutput::BeginDestroy() noexcept
void
FilteredAudioOutput
::
FinishDestroy
()
noexcept
{
ao_plugin_finish
(
output
);
output
.
reset
(
);
}
src/output/Init.cxx
View file @
31bad5f7
...
...
@@ -50,18 +50,11 @@
#define AUDIO_OUTPUT_FORMAT "format"
#define AUDIO_FILTERS "filters"
FilteredAudioOutput
::
FilteredAudioOutput
(
AudioOutput
&
_output
,
FilteredAudioOutput
::
FilteredAudioOutput
(
const
char
*
_plugin_name
,
std
::
unique_ptr
<
AudioOutput
>
&&
_output
,
const
ConfigBlock
&
block
)
:
output
(
&
_output
)
:
plugin_name
(
_plugin_name
),
output
(
std
::
move
(
_output
)
)
{
#ifndef NDEBUG
const
auto
&
plugin
=
output
->
GetPlugin
();
assert
(
plugin
.
finish
!=
nullptr
);
assert
(
plugin
.
open
!=
nullptr
);
assert
(
plugin
.
close
!=
nullptr
);
assert
(
plugin
.
play
!=
nullptr
);
#endif
Configure
(
block
);
}
...
...
@@ -172,7 +165,7 @@ FilteredAudioOutput::Configure(const ConfigBlock &block)
{
char
buffer
[
64
];
snprintf
(
buffer
,
sizeof
(
buffer
),
"
\"
%s
\"
(%s)"
,
name
,
output
->
GetPlugin
().
name
);
name
,
plugin_
name
);
log_name
=
buffer
;
}
...
...
@@ -204,6 +197,7 @@ FilteredAudioOutput::Configure(const ConfigBlock &block)
inline
void
FilteredAudioOutput
::
Setup
(
EventLoop
&
event_loop
,
const
ReplayGainConfig
&
replay_gain_config
,
const
MixerPlugin
*
mixer_plugin
,
MixerListener
&
mixer_listener
,
const
ConfigBlock
&
block
)
{
...
...
@@ -233,7 +227,7 @@ FilteredAudioOutput::Setup(EventLoop &event_loop,
try
{
mixer
=
audio_output_load_mixer
(
event_loop
,
*
this
,
block
,
output
->
GetPlugin
().
mixer_plugin
,
mixer_plugin
,
*
prepared_filter
,
mixer_listener
);
}
catch
(
const
std
::
runtime_error
&
e
)
{
...
...
@@ -291,20 +285,15 @@ audio_output_new(EventLoop &event_loop,
plugin
->
name
);
}
auto
*
ao
=
ao_plugin_init
(
event_loop
,
*
plugin
,
block
);
std
::
unique_ptr
<
AudioOutput
>
ao
(
ao_plugin_init
(
event_loop
,
*
plugin
,
block
));
assert
(
ao
!=
nullptr
);
FilteredAudioOutput
*
f
;
try
{
f
=
new
FilteredAudioOutput
(
*
ao
,
block
);
}
catch
(...)
{
ao_plugin_finish
(
ao
);
throw
;
}
auto
*
f
=
new
FilteredAudioOutput
(
plugin
->
name
,
std
::
move
(
ao
),
block
);
try
{
f
->
Setup
(
event_loop
,
replay_gain_config
,
plugin
->
mixer_plugin
,
mixer_listener
,
block
);
}
catch
(...)
{
delete
f
;
...
...
src/output/Interface.hxx
View file @
31bad5f7
...
...
@@ -20,22 +20,33 @@
#ifndef MPD_AUDIO_OUTPUT_INTERFACE_HXX
#define MPD_AUDIO_OUTPUT_INTERFACE_HXX
struct
AudioOutputPlugin
;
#include <chrono>
struct
AudioFormat
;
struct
Tag
;
class
AudioOutput
{
/**
* The plugin which implements this output device.
*/
const
AudioOutputPlugin
&
plugin
;
const
unsigned
flags
;
bool
need_fully_defined_audio_format
=
false
;
protected
:
static
constexpr
unsigned
FLAG_ENABLE_DISABLE
=
0x1
;
static
constexpr
unsigned
FLAG_PAUSE
=
0x2
;
public
:
AudioOutput
(
const
AudioOutputPlugin
&
_plugin
)
:
plugin
(
_plugin
)
{}
explicit
AudioOutput
(
unsigned
_flags
)
:
flags
(
_flags
)
{}
virtual
~
AudioOutput
()
=
default
;
AudioOutput
(
const
AudioOutput
&
)
=
delete
;
AudioOutput
&
operator
=
(
const
AudioOutput
&
)
=
delete
;
const
AudioOutputPlugin
&
GetPlugin
()
const
{
return
plugin
;
bool
SupportsEnableDisable
()
const
{
return
flags
&
FLAG_ENABLE_DISABLE
;
}
bool
SupportsPause
()
const
{
return
flags
&
FLAG_PAUSE
;
}
bool
GetNeedFullyDefinedAudioFormat
()
const
{
...
...
@@ -50,6 +61,87 @@ public:
void
NeedFullyDefinedAudioFormat
()
{
need_fully_defined_audio_format
=
true
;
}
/**
* Enable the device. This may allocate resources, preparing
* for the device to be opened.
*
* Throws #std::runtime_error on error.
*/
virtual
void
Enable
()
{}
/**
* Disables the device. It is closed before this method is
* called.
*/
virtual
void
Disable
()
noexcept
{}
/**
* Really open the device.
*
* Throws #std::runtime_error on error.
*
* @param audio_format the audio format in which data is going
* to be delivered; may be modified by the plugin
*/
virtual
void
Open
(
AudioFormat
&
audio_format
)
=
0
;
/**
* Close the device.
*/
virtual
void
Close
()
noexcept
=
0
;
/**
* Returns a positive number if the output thread shall further
* delay the next call to Play() or Pause(), which will happen
* until this function returns 0. This should be implemented
* instead of doing a sleep inside the plugin, because this
* allows MPD to listen to commands meanwhile.
*
* @return the duration to wait
*/
virtual
std
::
chrono
::
steady_clock
::
duration
Delay
()
const
noexcept
{
return
std
::
chrono
::
steady_clock
::
duration
::
zero
();
}
/**
* Display metadata for the next chunk. Optional method,
* because not all devices can display metadata.
*/
virtual
void
SendTag
(
const
Tag
&
)
{}
/**
* Play a chunk of audio data.
*
* Throws #std::runtime_error on error.
*
* @return the number of bytes played
*/
virtual
size_t
Play
(
const
void
*
chunk
,
size_t
size
)
=
0
;
/**
* Wait until the device has finished playing.
*/
virtual
void
Drain
()
{}
/**
* Try to cancel data which may still be in the device's
* buffers.
*/
virtual
void
Cancel
()
noexcept
{}
/**
* Pause the device. If supported, it may perform a special
* action, which keeps the device open, but does not play
* anything. Output plugins like "shout" might want to play
* silence during pause, so their clients won't be
* disconnected. Plugins which do not support pausing will
* simply be closed, and have to be reopened when unpaused.
*
* @return false on error (output will be closed by caller),
* true for continue to pause
*/
virtual
bool
Pause
()
noexcept
{
return
true
;
}
};
#endif
src/output/OutputPlugin.cxx
View file @
31bad5f7
...
...
@@ -19,7 +19,6 @@
#include "config.h"
#include "OutputPlugin.hxx"
#include "Interface.hxx"
#include <assert.h>
...
...
@@ -32,76 +31,3 @@ ao_plugin_init(EventLoop &event_loop,
return
plugin
.
init
(
event_loop
,
block
);
}
void
ao_plugin_finish
(
AudioOutput
*
ao
)
noexcept
{
ao
->
GetPlugin
().
finish
(
ao
);
}
void
ao_plugin_enable
(
AudioOutput
&
ao
)
{
if
(
ao
.
GetPlugin
().
enable
!=
nullptr
)
ao
.
GetPlugin
().
enable
(
&
ao
);
}
void
ao_plugin_disable
(
AudioOutput
&
ao
)
noexcept
{
if
(
ao
.
GetPlugin
().
disable
!=
nullptr
)
ao
.
GetPlugin
().
disable
(
&
ao
);
}
void
ao_plugin_open
(
AudioOutput
&
ao
,
AudioFormat
&
audio_format
)
{
ao
.
GetPlugin
().
open
(
&
ao
,
audio_format
);
}
void
ao_plugin_close
(
AudioOutput
&
ao
)
noexcept
{
ao
.
GetPlugin
().
close
(
&
ao
);
}
std
::
chrono
::
steady_clock
::
duration
ao_plugin_delay
(
AudioOutput
&
ao
)
noexcept
{
return
ao
.
GetPlugin
().
delay
!=
nullptr
?
ao
.
GetPlugin
().
delay
(
&
ao
)
:
std
::
chrono
::
steady_clock
::
duration
::
zero
();
}
void
ao_plugin_send_tag
(
AudioOutput
&
ao
,
const
Tag
&
tag
)
{
if
(
ao
.
GetPlugin
().
send_tag
!=
nullptr
)
ao
.
GetPlugin
().
send_tag
(
&
ao
,
tag
);
}
size_t
ao_plugin_play
(
AudioOutput
&
ao
,
const
void
*
chunk
,
size_t
size
)
{
return
ao
.
GetPlugin
().
play
(
&
ao
,
chunk
,
size
);
}
void
ao_plugin_drain
(
AudioOutput
&
ao
)
{
if
(
ao
.
GetPlugin
().
drain
!=
nullptr
)
ao
.
GetPlugin
().
drain
(
&
ao
);
}
void
ao_plugin_cancel
(
AudioOutput
&
ao
)
noexcept
{
if
(
ao
.
GetPlugin
().
cancel
!=
nullptr
)
ao
.
GetPlugin
().
cancel
(
&
ao
);
}
bool
ao_plugin_pause
(
AudioOutput
&
ao
)
{
return
ao
.
GetPlugin
().
pause
!=
nullptr
&&
ao
.
GetPlugin
().
pause
(
&
ao
);
}
src/output/OutputPlugin.hxx
View file @
31bad5f7
...
...
@@ -60,91 +60,6 @@ struct AudioOutputPlugin {
AudioOutput
*
(
*
init
)(
EventLoop
&
event_loop
,
const
ConfigBlock
&
block
);
/**
* Free resources allocated by this device.
*/
void
(
*
finish
)(
AudioOutput
*
data
);
/**
* Enable the device. This may allocate resources, preparing
* for the device to be opened.
*
* Throws #std::runtime_error on error.
*/
void
(
*
enable
)(
AudioOutput
*
data
);
/**
* Disables the device. It is closed before this method is
* called.
*/
void
(
*
disable
)(
AudioOutput
*
data
);
/**
* Really open the device.
*
* Throws #std::runtime_error on error.
*
* @param audio_format the audio format in which data is going
* to be delivered; may be modified by the plugin
*/
void
(
*
open
)(
AudioOutput
*
data
,
AudioFormat
&
audio_format
);
/**
* Close the device.
*/
void
(
*
close
)(
AudioOutput
*
data
);
/**
* Returns a positive number if the output thread shall further
* delay the next call to play() or pause(), which will happen
* until this function returns 0. This should be implemented
* instead of doing a sleep inside the plugin, because this
* allows MPD to listen to commands meanwhile.
*
* @return the duration to wait
*/
std
::
chrono
::
steady_clock
::
duration
(
*
delay
)(
AudioOutput
*
data
)
noexcept
;
/**
* Display metadata for the next chunk. Optional method,
* because not all devices can display metadata.
*/
void
(
*
send_tag
)(
AudioOutput
*
data
,
const
Tag
&
tag
);
/**
* Play a chunk of audio data.
*
* Throws #std::runtime_error on error.
*
* @return the number of bytes played
*/
size_t
(
*
play
)(
AudioOutput
*
data
,
const
void
*
chunk
,
size_t
size
);
/**
* Wait until the device has finished playing.
*/
void
(
*
drain
)(
AudioOutput
*
data
);
/**
* Try to cancel data which may still be in the device's
* buffers.
*/
void
(
*
cancel
)(
AudioOutput
*
data
);
/**
* Pause the device. If supported, it may perform a special
* action, which keeps the device open, but does not play
* anything. Output plugins like "shout" might want to play
* silence during pause, so their clients won't be
* disconnected. Plugins which do not support pausing will
* simply be closed, and have to be reopened when unpaused.
*
* @return false on error (output will be closed by caller),
* true for continue to pause
*/
bool
(
*
pause
)(
AudioOutput
*
data
);
/**
* The mixer plugin associated with this output plugin. This
* may be nullptr if no mixer plugin is implemented. When
* created, this mixer plugin gets the same #ConfigParam as
...
...
@@ -167,38 +82,4 @@ ao_plugin_init(EventLoop &event_loop,
const
AudioOutputPlugin
&
plugin
,
const
ConfigBlock
&
block
);
void
ao_plugin_finish
(
AudioOutput
*
ao
)
noexcept
;
void
ao_plugin_enable
(
AudioOutput
&
ao
);
void
ao_plugin_disable
(
AudioOutput
&
ao
)
noexcept
;
void
ao_plugin_open
(
AudioOutput
&
ao
,
AudioFormat
&
audio_format
);
void
ao_plugin_close
(
AudioOutput
&
ao
)
noexcept
;
gcc_pure
std
::
chrono
::
steady_clock
::
duration
ao_plugin_delay
(
AudioOutput
&
ao
)
noexcept
;
void
ao_plugin_send_tag
(
AudioOutput
&
ao
,
const
Tag
&
tag
);
size_t
ao_plugin_play
(
AudioOutput
&
ao
,
const
void
*
chunk
,
size_t
size
);
void
ao_plugin_drain
(
AudioOutput
&
ao
);
void
ao_plugin_cancel
(
AudioOutput
&
ao
)
noexcept
;
bool
ao_plugin_pause
(
AudioOutput
&
ao
);
#endif
src/output/Wrapper.hxx
deleted
100644 → 0
View file @
1cf7f3d8
/*
* 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_OUTPUT_WRAPPER_HXX
#define MPD_OUTPUT_WRAPPER_HXX
#include "Interface.hxx"
#include "util/Cast.hxx"
#include <chrono>
struct
ConfigBlock
;
struct
AudioFormat
;
struct
Tag
;
template
<
class
T
>
struct
AudioOutputWrapper
{
static
T
&
Cast
(
AudioOutput
&
ao
)
{
return
ContainerCast
(
ao
,
&
T
::
base
);
}
static
AudioOutput
*
Init
(
EventLoop
&
event_loop
,
const
ConfigBlock
&
block
)
{
T
*
t
=
T
::
Create
(
event_loop
,
block
);
return
&
t
->
base
;
}
static
void
Finish
(
AudioOutput
*
ao
)
{
T
*
t
=
&
Cast
(
*
ao
);
delete
t
;
}
static
void
Enable
(
AudioOutput
*
ao
)
{
T
&
t
=
Cast
(
*
ao
);
t
.
Enable
();
}
static
void
Disable
(
AudioOutput
*
ao
)
{
T
&
t
=
Cast
(
*
ao
);
t
.
Disable
();
}
static
void
Open
(
AudioOutput
*
ao
,
AudioFormat
&
audio_format
)
{
T
&
t
=
Cast
(
*
ao
);
t
.
Open
(
audio_format
);
}
static
void
Close
(
AudioOutput
*
ao
)
{
T
&
t
=
Cast
(
*
ao
);
t
.
Close
();
}
gcc_pure
static
std
::
chrono
::
steady_clock
::
duration
Delay
(
AudioOutput
*
ao
)
noexcept
{
T
&
t
=
Cast
(
*
ao
);
return
t
.
Delay
();
}
static
void
SendTag
(
AudioOutput
*
ao
,
const
Tag
&
tag
)
{
T
&
t
=
Cast
(
*
ao
);
t
.
SendTag
(
tag
);
}
static
size_t
Play
(
AudioOutput
*
ao
,
const
void
*
chunk
,
size_t
size
)
{
T
&
t
=
Cast
(
*
ao
);
return
t
.
Play
(
chunk
,
size
);
}
static
void
Drain
(
AudioOutput
*
ao
)
{
T
&
t
=
Cast
(
*
ao
);
t
.
Drain
();
}
static
void
Cancel
(
AudioOutput
*
ao
)
{
T
&
t
=
Cast
(
*
ao
);
t
.
Cancel
();
}
static
bool
Pause
(
AudioOutput
*
ao
)
{
T
&
t
=
Cast
(
*
ao
);
return
t
.
Pause
();
}
};
#endif
src/output/plugins/AlsaOutputPlugin.cxx
View file @
31bad5f7
...
...
@@ -22,7 +22,6 @@
#include "lib/alsa/NonBlock.hxx"
#include "lib/alsa/Version.hxx"
#include "../OutputAPI.hxx"
#include "../Wrapper.hxx"
#include "mixer/MixerList.hxx"
#include "pcm/PcmExport.hxx"
#include "system/ByteOrder.hxx"
...
...
@@ -60,11 +59,7 @@ static constexpr unsigned MPD_ALSA_BUFFER_TIME_US = 500000;
static
constexpr
unsigned
MPD_ALSA_RETRY_NR
=
5
;
class
AlsaOutput
final
:
MultiSocketMonitor
,
DeferredMonitor
{
friend
struct
AudioOutputWrapper
<
AlsaOutput
>
;
AudioOutput
base
;
:
AudioOutput
,
MultiSocketMonitor
,
DeferredMonitor
{
Manual
<
PcmExport
>
pcm_export
;
...
...
@@ -290,20 +285,22 @@ public:
return
device
.
empty
()
?
default_device
:
device
.
c_str
();
}
static
AlsaOutput
*
Create
(
EventLoop
&
event_loop
,
const
ConfigBlock
&
block
);
static
AudioOutput
*
Create
(
EventLoop
&
event_loop
,
const
ConfigBlock
&
block
)
{
return
new
AlsaOutput
(
event_loop
,
block
);
}
void
Enable
();
void
Disable
();
private
:
void
Enable
()
override
;
void
Disable
()
noexcept
override
;
void
Open
(
AudioFormat
&
audio_format
);
void
Close
();
void
Open
(
AudioFormat
&
audio_format
)
override
;
void
Close
()
noexcept
override
;
size_t
Play
(
const
void
*
chunk
,
size_t
size
);
void
Drain
();
void
Cancel
();
size_t
Play
(
const
void
*
chunk
,
size_t
size
)
override
;
void
Drain
()
override
;
void
Cancel
()
noexcept
override
;
private
:
/**
* Set up the snd_pcm_t object which was opened by the caller.
* Set up the configured settings and the audio format.
...
...
@@ -413,8 +410,8 @@ private:
static
constexpr
Domain
alsa_output_domain
(
"alsa_output"
);
AlsaOutput
::
AlsaOutput
(
EventLoop
&
loop
,
const
ConfigBlock
&
block
)
:
MultiSocketMonitor
(
loop
),
DeferredMonitor
(
loop
),
base
(
alsa_output_plugin
),
:
AudioOutput
(
FLAG_ENABLE_DISABLE
),
MultiSocketMonitor
(
loop
),
DeferredMonitor
(
loop
),
device
(
block
.
GetBlockValue
(
"device"
,
""
)),
#ifdef ENABLE_DSD
dop
(
block
.
GetBlockValue
(
"dop"
,
false
)
||
...
...
@@ -441,20 +438,14 @@ AlsaOutput::AlsaOutput(EventLoop &loop, const ConfigBlock &block)
#endif
}
inline
AlsaOutput
*
AlsaOutput
::
Create
(
EventLoop
&
event_loop
,
const
ConfigBlock
&
block
)
{
return
new
AlsaOutput
(
event_loop
,
block
);
}
inline
void
void
AlsaOutput
::
Enable
()
{
pcm_export
.
Construct
();
}
inline
void
AlsaOutput
::
Disable
()
void
AlsaOutput
::
Disable
()
noexcept
{
pcm_export
.
Destruct
();
}
...
...
@@ -1015,7 +1006,7 @@ MaybeDmix(snd_pcm_t *pcm) noexcept
return
MaybeDmix
(
snd_pcm_type
(
pcm
));
}
inline
void
void
AlsaOutput
::
Open
(
AudioFormat
&
audio_format
)
{
int
err
=
snd_pcm_open
(
&
pcm
,
GetDevice
(),
...
...
@@ -1158,7 +1149,7 @@ AlsaOutput::DrainInternal()
return
snd_pcm_drain
(
pcm
)
!=
-
EAGAIN
;
}
inline
void
void
AlsaOutput
::
Drain
()
{
const
std
::
lock_guard
<
Mutex
>
lock
(
mutex
);
...
...
@@ -1183,8 +1174,8 @@ AlsaOutput::CancelInternal()
ClearRingBuffer
();
}
inline
void
AlsaOutput
::
Cancel
()
void
AlsaOutput
::
Cancel
()
noexcept
{
if
(
!
active
)
{
/* early cancel, quick code path without thread
...
...
@@ -1202,8 +1193,8 @@ AlsaOutput::Cancel()
});
}
inline
void
AlsaOutput
::
Close
()
void
AlsaOutput
::
Close
()
noexcept
{
/* make sure the I/O thread isn't inside DispatchSockets() */
BlockingCall
(
MultiSocketMonitor
::
GetEventLoop
(),
[
this
](){
...
...
@@ -1217,7 +1208,7 @@ AlsaOutput::Close()
delete
[]
silence
;
}
inline
size_t
size_t
AlsaOutput
::
Play
(
const
void
*
chunk
,
size_t
size
)
{
assert
(
size
>
0
);
...
...
@@ -1331,23 +1322,9 @@ try {
cond
.
signal
();
}
typedef
AudioOutputWrapper
<
AlsaOutput
>
Wrapper
;
const
struct
AudioOutputPlugin
alsa_output_plugin
=
{
"alsa"
,
alsa_test_default_device
,
&
Wrapper
::
Init
,
&
Wrapper
::
Finish
,
&
Wrapper
::
Enable
,
&
Wrapper
::
Disable
,
&
Wrapper
::
Open
,
&
Wrapper
::
Close
,
nullptr
,
nullptr
,
&
Wrapper
::
Play
,
&
Wrapper
::
Drain
,
&
Wrapper
::
Cancel
,
nullptr
,
&
AlsaOutput
::
Create
,
&
alsa_mixer_plugin
,
};
src/output/plugins/AoOutputPlugin.cxx
View file @
31bad5f7
...
...
@@ -20,7 +20,6 @@
#include "config.h"
#include "AoOutputPlugin.hxx"
#include "../OutputAPI.hxx"
#include "../Wrapper.hxx"
#include "system/Error.hxx"
#include "util/DivideString.hxx"
#include "util/SplitString.hxx"
...
...
@@ -37,11 +36,7 @@ static ao_sample_format OUR_AO_FORMAT_INITIALIZER;
static
unsigned
ao_output_ref
;
class
AoOutput
{
friend
struct
AudioOutputWrapper
<
AoOutput
>
;
AudioOutput
base
;
class
AoOutput
final
:
AudioOutput
{
const
size_t
write_size
;
int
driver
;
ao_option
*
options
=
nullptr
;
...
...
@@ -51,14 +46,14 @@ class AoOutput {
~
AoOutput
();
public
:
static
AoOutput
*
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
static
A
udi
oOutput
*
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
return
new
AoOutput
(
block
);
}
void
Open
(
AudioFormat
&
audio_format
);
void
Close
();
void
Open
(
AudioFormat
&
audio_format
)
override
;
void
Close
()
noexcept
override
;
size_t
Play
(
const
void
*
chunk
,
size_t
size
);
size_t
Play
(
const
void
*
chunk
,
size_t
size
)
override
;
};
static
constexpr
Domain
ao_output_domain
(
"ao_output"
);
...
...
@@ -95,7 +90,7 @@ MakeAoError()
}
AoOutput
::
AoOutput
(
const
ConfigBlock
&
block
)
:
base
(
ao_output_plugin
),
:
AudioOutput
(
0
),
write_size
(
block
.
GetBlockValue
(
"write_size"
,
1024u
))
{
if
(
ao_output_ref
==
0
)
{
...
...
@@ -177,7 +172,7 @@ AoOutput::Open(AudioFormat &audio_format)
}
void
AoOutput
::
Close
()
AoOutput
::
Close
()
noexcept
{
ao_close
(
device
);
}
...
...
@@ -199,22 +194,9 @@ AoOutput::Play(const void *chunk, size_t size)
return
size
;
}
typedef
AudioOutputWrapper
<
AoOutput
>
Wrapper
;
const
struct
AudioOutputPlugin
ao_output_plugin
=
{
"ao"
,
nullptr
,
&
Wrapper
::
Init
,
&
Wrapper
::
Finish
,
nullptr
,
nullptr
,
&
Wrapper
::
Open
,
&
Wrapper
::
Close
,
nullptr
,
nullptr
,
&
Wrapper
::
Play
,
nullptr
,
nullptr
,
nullptr
,
&
AoOutput
::
Create
,
nullptr
,
};
src/output/plugins/FifoOutputPlugin.cxx
View file @
31bad5f7
...
...
@@ -20,7 +20,6 @@
#include "config.h"
#include "FifoOutputPlugin.hxx"
#include "../OutputAPI.hxx"
#include "../Wrapper.hxx"
#include "../Timer.hxx"
#include "fs/AllocatedPath.hxx"
#include "fs/FileSystem.hxx"
...
...
@@ -34,11 +33,7 @@
#include <errno.h>
#include <unistd.h>
class
FifoOutput
{
friend
struct
AudioOutputWrapper
<
FifoOutput
>
;
AudioOutput
base
;
class
FifoOutput
final
:
AudioOutput
{
const
AllocatedPath
path
;
std
::
string
path_utf8
;
...
...
@@ -54,9 +49,12 @@ public:
CloseFifo
();
}
static
FifoOutput
*
Create
(
EventLoop
&
event_loop
,
const
ConfigBlock
&
block
);
static
AudioOutput
*
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
return
new
FifoOutput
(
block
);
}
private
:
void
Create
();
void
Check
();
void
Delete
();
...
...
@@ -64,18 +62,18 @@ public:
void
OpenFifo
();
void
CloseFifo
();
void
Open
(
AudioFormat
&
audio_format
);
void
Close
();
void
Open
(
AudioFormat
&
audio_format
)
override
;
void
Close
()
noexcept
override
;
std
::
chrono
::
steady_clock
::
duration
Delay
()
const
noexcept
;
size_t
Play
(
const
void
*
chunk
,
size_t
size
);
void
Cancel
();
std
::
chrono
::
steady_clock
::
duration
Delay
()
const
noexcept
override
;
size_t
Play
(
const
void
*
chunk
,
size_t
size
)
override
;
void
Cancel
()
noexcept
override
;
};
static
constexpr
Domain
fifo_output_domain
(
"fifo_output"
);
FifoOutput
::
FifoOutput
(
const
ConfigBlock
&
block
)
:
base
(
fifo_output_plugin
),
:
AudioOutput
(
0
),
path
(
block
.
GetPath
(
"path"
))
{
if
(
path
.
IsNull
())
...
...
@@ -169,12 +167,6 @@ try {
throw
;
}
inline
FifoOutput
*
FifoOutput
::
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
return
new
FifoOutput
(
block
);
}
void
FifoOutput
::
Open
(
AudioFormat
&
audio_format
)
{
...
...
@@ -182,13 +174,13 @@ FifoOutput::Open(AudioFormat &audio_format)
}
void
FifoOutput
::
Close
()
FifoOutput
::
Close
()
noexcept
{
delete
timer
;
}
inline
void
FifoOutput
::
Cancel
()
void
FifoOutput
::
Cancel
()
noexcept
{
timer
->
Reset
();
...
...
@@ -205,7 +197,7 @@ FifoOutput::Cancel()
}
}
inline
std
::
chrono
::
steady_clock
::
duration
std
::
chrono
::
steady_clock
::
duration
FifoOutput
::
Delay
()
const
noexcept
{
return
timer
->
IsStarted
()
...
...
@@ -213,7 +205,7 @@ FifoOutput::Delay() const noexcept
:
std
::
chrono
::
steady_clock
::
duration
::
zero
();
}
inline
size_t
size_t
FifoOutput
::
Play
(
const
void
*
chunk
,
size_t
size
)
{
if
(
!
timer
->
IsStarted
())
...
...
@@ -241,22 +233,9 @@ FifoOutput::Play(const void *chunk, size_t size)
}
}
typedef
AudioOutputWrapper
<
FifoOutput
>
Wrapper
;
const
struct
AudioOutputPlugin
fifo_output_plugin
=
{
"fifo"
,
nullptr
,
&
Wrapper
::
Init
,
&
Wrapper
::
Finish
,
nullptr
,
nullptr
,
&
Wrapper
::
Open
,
&
Wrapper
::
Close
,
&
Wrapper
::
Delay
,
nullptr
,
&
Wrapper
::
Play
,
nullptr
,
&
Wrapper
::
Cancel
,
nullptr
,
&
FifoOutput
::
Create
,
nullptr
,
};
src/output/plugins/HaikuOutputPlugin.cxx
View file @
31bad5f7
...
...
@@ -21,7 +21,6 @@
#include "config.h"
#include "HaikuOutputPlugin.hxx"
#include "../OutputAPI.hxx"
#include "../Wrapper.hxx"
#include "mixer/MixerList.hxx"
#include "util/Domain.hxx"
#include "system/Error.hxx"
...
...
@@ -43,13 +42,10 @@
#define UTF8_PLAY "\xE2\x96\xB6"
class
HaikuOutput
{
friend
struct
AudioOutputWrapper
<
HaikuOutput
>
;
class
HaikuOutput
final
:
AudioOutput
{
friend
int
haiku_output_get_volume
(
HaikuOutput
&
haiku
);
friend
bool
haiku_output_set_volume
(
HaikuOutput
&
haiku
,
unsigned
volume
);
AudioOutput
base
;
size_t
write_size
;
media_raw_audio_format
format
;
...
...
@@ -66,27 +62,28 @@ class HaikuOutput {
public
:
HaikuOutput
(
const
ConfigBlock
&
block
)
:
base
(
haiku_output_plugin
),
:
AudioOutput
(
0
),
/* XXX: by default we should let the MediaKit propose the buffer size */
write_size
(
block
.
GetBlockValue
(
"write_size"
,
4096u
))
{}
~
HaikuOutput
();
static
Haiku
Output
*
Create
(
EventLoop
&
event_loop
,
static
Audio
Output
*
Create
(
EventLoop
&
event_loop
,
const
ConfigBlock
&
block
);
void
Open
(
AudioFormat
&
audio_format
);
void
Close
();
private
:
void
Open
(
AudioFormat
&
audio_format
)
override
;
void
Close
()
noexcept
override
;
size_t
Play
(
const
void
*
chunk
,
size_t
size
);
void
Cancel
();
size_t
Play
(
const
void
*
chunk
,
size_t
size
)
override
;
void
Cancel
()
noexcept
override
;
std
::
chrono
::
steady_clock
::
duration
Delay
()
noexcept
;
std
::
chrono
::
steady_clock
::
duration
Delay
()
const
noexcept
override
;
void
FillBuffer
(
void
*
_buffer
,
size_t
size
,
gcc_unused
const
media_raw_audio_format
&
_format
);
void
SendTag
(
const
Tag
&
tag
);
void
SendTag
(
const
Tag
&
tag
)
override
;
};
static
constexpr
Domain
haiku_output_domain
(
"haiku_output"
);
...
...
@@ -120,7 +117,7 @@ haiku_test_default_device(void)
}
inline
Haiku
Output
*
inline
Audio
Output
*
HaikuOutput
::
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
initialize_application
();
...
...
@@ -129,7 +126,7 @@ HaikuOutput::Create(EventLoop &, const ConfigBlock &block)
}
void
HaikuOutput
::
Close
()
HaikuOutput
::
Close
()
noexcept
{
sound_player
->
SetHasData
(
false
);
delete_sem
(
new_buffer
);
...
...
@@ -139,8 +136,6 @@ HaikuOutput::Close()
sound_player
=
nullptr
;
}
HaikuOutput
::~
HaikuOutput
()
{
delete_sem
(
new_buffer
);
...
...
@@ -186,7 +181,7 @@ HaikuOutput::FillBuffer(void* _buffer, size_t size,
}
}
inline
void
void
HaikuOutput
::
Open
(
AudioFormat
&
audio_format
)
{
status_t
err
;
...
...
@@ -265,7 +260,7 @@ HaikuOutput::Open(AudioFormat &audio_format)
sound_player
->
SetHasData
(
false
);
}
inline
size_t
size_t
HaikuOutput
::
Play
(
const
void
*
chunk
,
size_t
size
)
{
BSoundPlayer
*
const
soundPlayer
=
sound_player
;
...
...
@@ -311,7 +306,7 @@ HaikuOutput::Play(const void *chunk, size_t size)
}
inline
std
::
chrono
::
steady_clock
::
duration
HaikuOutput
::
Delay
()
noexcept
HaikuOutput
::
Delay
()
const
noexcept
{
unsigned
delay
=
buffer_filled
?
0
:
buffer_delay
;
...
...
@@ -324,7 +319,7 @@ HaikuOutput::Delay() noexcept
return
std
::
chrono
::
steady_clock
::
duration
::
zero
();
}
inline
void
void
HaikuOutput
::
SendTag
(
const
Tag
&
tag
)
{
status_t
err
;
...
...
@@ -468,18 +463,6 @@ typedef AudioOutputWrapper<HaikuOutput> Wrapper;
const
struct
AudioOutputPlugin
haiku_output_plugin
=
{
"haiku"
,
haiku_test_default_device
,
&
Wrapper
::
Init
,
&
Wrapper
::
Finish
,
nullptr
,
nullptr
,
&
Wrapper
::
Open
,
&
Wrapper
::
Close
,
&
Wrapper
::
Delay
,
&
Wrapper
::
SendTag
,
&
Wrapper
::
Play
,
nullptr
,
nullptr
,
nullptr
,
&
HaikuOutput
::
Create
,
&
haiku_mixer_plugin
,
};
src/output/plugins/JackOutputPlugin.cxx
View file @
31bad5f7
...
...
@@ -20,7 +20,6 @@
#include "config.h"
#include "JackOutputPlugin.hxx"
#include "../OutputAPI.hxx"
#include "../Wrapper.hxx"
#include "config/ConfigError.hxx"
#include "util/ScopeExit.hxx"
#include "util/ConstBuffer.hxx"
...
...
@@ -42,9 +41,7 @@ static constexpr unsigned MAX_PORTS = 16;
static
constexpr
size_t
jack_sample_size
=
sizeof
(
jack_default_audio_sample_t
);
struct
JackOutput
{
AudioOutput
base
;
struct
JackOutput
final
:
AudioOutput
{
/**
* libjack options passed to jack_client_open().
*/
...
...
@@ -99,12 +96,12 @@ struct JackOutput {
shutdown
=
true
;
}
void
Enable
();
void
Disable
();
void
Enable
()
override
;
void
Disable
()
noexcept
override
;
void
Open
(
AudioFormat
&
new_audio_format
);
void
Open
(
AudioFormat
&
new_audio_format
)
override
;
void
Close
()
{
void
Close
()
noexcept
override
{
Stop
();
}
...
...
@@ -128,15 +125,15 @@ struct JackOutput {
*/
size_t
WriteSamples
(
const
float
*
src
,
size_t
n_frames
);
std
::
chrono
::
steady_clock
::
duration
Delay
()
const
noexcept
{
std
::
chrono
::
steady_clock
::
duration
Delay
()
const
noexcept
override
{
return
pause
&&
!
shutdown
?
std
::
chrono
::
seconds
(
1
)
:
std
::
chrono
::
steady_clock
::
duration
::
zero
();
}
size_t
Play
(
const
void
*
chunk
,
size_t
size
);
size_t
Play
(
const
void
*
chunk
,
size_t
size
)
override
;
bool
Pause
();
bool
Pause
()
noexcept
override
;
};
static
constexpr
Domain
jack_output_domain
(
"jack_output"
);
...
...
@@ -162,7 +159,7 @@ parse_port_list(const char *source, std::string dest[])
}
JackOutput
::
JackOutput
(
const
ConfigBlock
&
block
)
:
base
(
jack_output_plugin
),
:
AudioOutput
(
FLAG_ENABLE_DISABLE
|
FLAG_PAUSE
),
name
(
block
.
GetBlockValue
(
"client_name"
,
nullptr
)),
server_name
(
block
.
GetBlockValue
(
"server_name"
,
nullptr
))
{
...
...
@@ -430,7 +427,7 @@ JackOutput::Enable()
}
inline
void
JackOutput
::
Disable
()
JackOutput
::
Disable
()
noexcept
{
if
(
client
!=
nullptr
)
Disconnect
();
...
...
@@ -452,8 +449,7 @@ mpd_jack_init(EventLoop &, const ConfigBlock &block)
jack_set_info_function
(
mpd_jack_info
);
#endif
auto
*
jd
=
new
JackOutput
(
block
);
return
&
jd
->
base
;
return
new
JackOutput
(
block
);
}
/**
...
...
@@ -663,7 +659,7 @@ JackOutput::Play(const void *chunk, size_t size)
}
inline
bool
JackOutput
::
Pause
()
JackOutput
::
Pause
()
noexcept
{
if
(
shutdown
)
return
false
;
...
...
@@ -673,22 +669,9 @@ JackOutput::Pause()
return
true
;
}
typedef
AudioOutputWrapper
<
JackOutput
>
Wrapper
;
const
struct
AudioOutputPlugin
jack_output_plugin
=
{
"jack"
,
mpd_jack_test_default_device
,
mpd_jack_init
,
&
Wrapper
::
Finish
,
&
Wrapper
::
Enable
,
&
Wrapper
::
Disable
,
&
Wrapper
::
Open
,
&
Wrapper
::
Close
,
&
Wrapper
::
Delay
,
nullptr
,
&
Wrapper
::
Play
,
nullptr
,
nullptr
,
&
Wrapper
::
Pause
,
nullptr
,
};
src/output/plugins/NullOutputPlugin.cxx
View file @
31bad5f7
...
...
@@ -20,43 +20,41 @@
#include "config.h"
#include "NullOutputPlugin.hxx"
#include "../OutputAPI.hxx"
#include "../Wrapper.hxx"
#include "../Timer.hxx"
class
NullOutput
{
friend
struct
AudioOutputWrapper
<
NullOutput
>
;
AudioOutput
base
;
class
NullOutput
final
:
AudioOutput
{
const
bool
sync
;
Timer
*
timer
;
public
:
NullOutput
(
const
ConfigBlock
&
block
)
:
base
(
null_output_plugin
),
:
AudioOutput
(
0
),
sync
(
block
.
GetBlockValue
(
"sync"
,
true
))
{}
static
NullOutput
*
Create
(
EventLoop
&
event_loop
,
const
ConfigBlock
&
block
);
static
AudioOutput
*
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
return
new
NullOutput
(
block
);
}
void
Open
(
AudioFormat
&
audio_format
)
{
private
:
void
Open
(
AudioFormat
&
audio_format
)
override
{
if
(
sync
)
timer
=
new
Timer
(
audio_format
);
}
void
Close
()
{
void
Close
()
noexcept
override
{
if
(
sync
)
delete
timer
;
}
std
::
chrono
::
steady_clock
::
duration
Delay
()
const
noexcept
{
std
::
chrono
::
steady_clock
::
duration
Delay
()
const
noexcept
override
{
return
sync
&&
timer
->
IsStarted
()
?
timer
->
GetDelay
()
:
std
::
chrono
::
steady_clock
::
duration
::
zero
();
}
size_t
Play
(
gcc_unused
const
void
*
chunk
,
size_t
size
)
{
size_t
Play
(
gcc_unused
const
void
*
chunk
,
size_t
size
)
override
{
if
(
sync
)
{
if
(
!
timer
->
IsStarted
())
timer
->
Start
();
...
...
@@ -66,34 +64,15 @@ public:
return
size
;
}
void
Cancel
()
{
void
Cancel
()
noexcept
override
{
if
(
sync
)
timer
->
Reset
();
}
};
inline
NullOutput
*
NullOutput
::
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
return
new
NullOutput
(
block
);
}
typedef
AudioOutputWrapper
<
NullOutput
>
Wrapper
;
const
struct
AudioOutputPlugin
null_output_plugin
=
{
"null"
,
nullptr
,
&
Wrapper
::
Init
,
&
Wrapper
::
Finish
,
nullptr
,
nullptr
,
&
Wrapper
::
Open
,
&
Wrapper
::
Close
,
&
Wrapper
::
Delay
,
nullptr
,
&
Wrapper
::
Play
,
nullptr
,
&
Wrapper
::
Cancel
,
nullptr
,
&
NullOutput
::
Create
,
nullptr
,
};
src/output/plugins/OSXOutputPlugin.cxx
View file @
31bad5f7
...
...
@@ -35,9 +35,7 @@
#include <memory>
struct
OSXOutput
{
AudioOutput
base
;
struct
OSXOutput
final
:
AudioOutput
{
/* configuration settings */
OSType
component_subtype
;
/* only applicable with kAudioUnitSubType_HALOutput */
...
...
@@ -53,6 +51,18 @@ struct OSXOutput {
boost
::
lockfree
::
spsc_queue
<
uint8_t
>
*
ring_buffer
;
OSXOutput
(
const
ConfigBlock
&
block
);
static
AudioOutput
*
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
);
private
:
void
Enable
()
override
;
void
Disable
()
noexcept
override
;
void
Open
(
AudioFormat
&
audio_format
)
override
;
void
Close
()
noexcept
override
;
std
::
chrono
::
steady_clock
::
duration
Delay
()
const
noexcept
override
;
size_t
Play
(
const
void
*
chunk
,
size_t
size
)
override
;
};
static
constexpr
Domain
osx_output_domain
(
"osx_output"
);
...
...
@@ -80,7 +90,7 @@ osx_output_test_default_device(void)
}
OSXOutput
::
OSXOutput
(
const
ConfigBlock
&
block
)
:
base
(
osx_output_plugin
)
:
AudioOutput
(
FLAG_ENABLE_DISABLE
)
{
const
char
*
device
=
block
.
GetBlockValue
(
"device"
);
...
...
@@ -103,8 +113,8 @@ OSXOutput::OSXOutput(const ConfigBlock &block)
sync_sample_rate
=
block
.
GetBlockValue
(
"sync_sample_rate"
,
false
);
}
static
AudioOutput
*
osx_output_init
(
EventLoop
&
,
const
ConfigBlock
&
block
)
AudioOutput
*
OSXOutput
::
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
OSXOutput
*
oo
=
new
OSXOutput
(
block
);
...
...
@@ -124,15 +134,7 @@ osx_output_init(EventLoop &, const ConfigBlock &block)
&
dev_id
);
oo
->
dev_id
=
dev_id
;
return
&
oo
->
base
;
}
static
void
osx_output_finish
(
AudioOutput
*
ao
)
{
OSXOutput
*
oo
=
(
OSXOutput
*
)
ao
;
delete
oo
;
return
oo
;
}
static
void
...
...
@@ -513,15 +515,14 @@ osx_render(void *vdata,
return
noErr
;
}
static
void
osx_output_enable
(
AudioOutput
*
ao
)
void
OSXOutput
::
Enable
(
)
{
char
errormsg
[
1024
];
OSXOutput
*
oo
=
(
OSXOutput
*
)
ao
;
AudioComponentDescription
desc
;
desc
.
componentType
=
kAudioUnitType_Output
;
desc
.
componentSubType
=
oo
->
component_subtype
;
desc
.
componentSubType
=
component_subtype
;
desc
.
componentManufacturer
=
kAudioUnitManufacturer_Apple
;
desc
.
componentFlags
=
0
;
desc
.
componentFlagsMask
=
0
;
...
...
@@ -530,7 +531,7 @@ osx_output_enable(AudioOutput *ao)
if
(
comp
==
0
)
throw
std
::
runtime_error
(
"Error finding OS X component"
);
OSStatus
status
=
AudioComponentInstanceNew
(
comp
,
&
oo
->
au
);
OSStatus
status
=
AudioComponentInstanceNew
(
comp
,
&
au
);
if
(
status
!=
noErr
)
{
osx_os_status_to_cstring
(
status
,
errormsg
,
sizeof
(
errormsg
));
throw
FormatRuntimeError
(
"Unable to open OS X component: %s"
,
...
...
@@ -538,105 +539,97 @@ osx_output_enable(AudioOutput *ao)
}
try
{
osx_output_set_device
(
oo
);
osx_output_set_device
(
this
);
}
catch
(...)
{
AudioComponentInstanceDispose
(
oo
->
au
);
AudioComponentInstanceDispose
(
au
);
throw
;
}
if
(
oo
->
hog_device
)
{
osx_output_hog_device
(
oo
->
dev_id
,
true
);
}
if
(
hog_device
)
osx_output_hog_device
(
dev_id
,
true
);
}
static
void
osx_output_disable
(
AudioOutput
*
ao
)
void
OSXOutput
::
Disable
()
noexcept
{
OSXOutput
*
oo
=
(
OSXOutput
*
)
ao
;
AudioComponentInstanceDispose
(
oo
->
au
);
AudioComponentInstanceDispose
(
au
);
if
(
oo
->
hog_device
)
{
osx_output_hog_device
(
oo
->
dev_id
,
false
);
}
if
(
hog_device
)
osx_output_hog_device
(
dev_id
,
false
);
}
static
void
osx_output_close
(
AudioOutput
*
ao
)
void
OSXOutput
::
Close
()
noexcept
{
OSXOutput
*
od
=
(
OSXOutput
*
)
ao
;
AudioOutputUnitStop
(
od
->
au
);
AudioUnitUninitialize
(
od
->
au
);
AudioOutputUnitStop
(
au
);
AudioUnitUninitialize
(
au
);
delete
od
->
ring_buffer
;
delete
ring_buffer
;
}
static
void
osx_output_open
(
AudioOutput
*
ao
,
AudioFormat
&
audio_format
)
void
OSXOutput
::
Open
(
AudioFormat
&
audio_format
)
{
char
errormsg
[
1024
];
OSXOutput
*
od
=
(
OSXOutput
*
)
ao
;
memset
(
&
od
->
asbd
,
0
,
sizeof
(
od
->
asbd
));
od
->
asbd
.
mSampleRate
=
audio_format
.
sample_rate
;
od
->
asbd
.
mFormatID
=
kAudioFormatLinearPCM
;
od
->
asbd
.
mFormatFlags
=
kLinearPCMFormatFlagIsSignedInteger
;
memset
(
&
asbd
,
0
,
sizeof
(
asbd
));
asbd
.
mSampleRate
=
audio_format
.
sample_rate
;
asbd
.
mFormatID
=
kAudioFormatLinearPCM
;
asbd
.
mFormatFlags
=
kLinearPCMFormatFlagIsSignedInteger
;
switch
(
audio_format
.
format
)
{
case
SampleFormat
:
:
S8
:
od
->
asbd
.
mBitsPerChannel
=
8
;
asbd
.
mBitsPerChannel
=
8
;
break
;
case
SampleFormat
:
:
S16
:
od
->
asbd
.
mBitsPerChannel
=
16
;
asbd
.
mBitsPerChannel
=
16
;
break
;
case
SampleFormat
:
:
S32
:
od
->
asbd
.
mBitsPerChannel
=
32
;
asbd
.
mBitsPerChannel
=
32
;
break
;
default
:
audio_format
.
format
=
SampleFormat
::
S32
;
od
->
asbd
.
mBitsPerChannel
=
32
;
asbd
.
mBitsPerChannel
=
32
;
break
;
}
if
(
IsBigEndian
())
od
->
asbd
.
mFormatFlags
|=
kLinearPCMFormatFlagIsBigEndian
;
asbd
.
mFormatFlags
|=
kLinearPCMFormatFlagIsBigEndian
;
od
->
asbd
.
mBytesPerPacket
=
audio_format
.
GetFrameSize
();
od
->
asbd
.
mFramesPerPacket
=
1
;
od
->
asbd
.
mBytesPerFrame
=
od
->
asbd
.
mBytesPerPacket
;
od
->
asbd
.
mChannelsPerFrame
=
audio_format
.
channels
;
asbd
.
mBytesPerPacket
=
audio_format
.
GetFrameSize
();
asbd
.
mFramesPerPacket
=
1
;
asbd
.
mBytesPerFrame
=
asbd
.
mBytesPerPacket
;
asbd
.
mChannelsPerFrame
=
audio_format
.
channels
;
if
(
od
->
sync_sample_rate
)
{
osx_output_sync_device_sample_rate
(
od
->
dev_id
,
od
->
asbd
);
}
if
(
sync_sample_rate
)
osx_output_sync_device_sample_rate
(
dev_id
,
asbd
);
OSStatus
status
=
AudioUnitSetProperty
(
od
->
au
,
kAudioUnitProperty_StreamFormat
,
AudioUnitSetProperty
(
au
,
kAudioUnitProperty_StreamFormat
,
kAudioUnitScope_Input
,
0
,
&
od
->
asbd
,
sizeof
(
od
->
asbd
));
&
asbd
,
sizeof
(
asbd
));
if
(
status
!=
noErr
)
throw
std
::
runtime_error
(
"Unable to set format on OS X device"
);
AURenderCallbackStruct
callback
;
callback
.
inputProc
=
osx_render
;
callback
.
inputProcRefCon
=
od
;
callback
.
inputProcRefCon
=
this
;
status
=
AudioUnitSetProperty
(
od
->
au
,
AudioUnitSetProperty
(
au
,
kAudioUnitProperty_SetRenderCallback
,
kAudioUnitScope_Input
,
0
,
&
callback
,
sizeof
(
callback
));
if
(
status
!=
noErr
)
{
AudioComponentInstanceDispose
(
od
->
au
);
AudioComponentInstanceDispose
(
au
);
throw
std
::
runtime_error
(
"unable to set callback for OS X audio unit"
);
}
status
=
AudioUnitInitialize
(
od
->
au
);
status
=
AudioUnitInitialize
(
au
);
if
(
status
!=
noErr
)
{
osx_os_status_to_cstring
(
status
,
errormsg
,
sizeof
(
errormsg
));
throw
FormatRuntimeError
(
"Unable to initialize OS X audio unit: %s"
,
...
...
@@ -644,36 +637,34 @@ osx_output_open(AudioOutput *ao, AudioFormat &audio_format)
}
UInt32
buffer_frame_size
=
1
;
status
=
osx_output_set_buffer_size
(
od
->
au
,
od
->
asbd
,
&
buffer_frame_size
);
status
=
osx_output_set_buffer_size
(
au
,
asbd
,
&
buffer_frame_size
);
if
(
status
!=
noErr
)
{
osx_os_status_to_cstring
(
status
,
errormsg
,
sizeof
(
errormsg
));
throw
FormatRuntimeError
(
"Unable to set frame size: %s"
,
errormsg
);
}
od
->
ring_buffer
=
new
boost
::
lockfree
::
spsc_queue
<
uint8_t
>
(
buffer_frame_size
);
ring_buffer
=
new
boost
::
lockfree
::
spsc_queue
<
uint8_t
>
(
buffer_frame_size
);
status
=
AudioOutputUnitStart
(
od
->
au
);
status
=
AudioOutputUnitStart
(
au
);
if
(
status
!=
0
)
{
AudioUnitUninitialize
(
od
->
au
);
AudioUnitUninitialize
(
au
);
osx_os_status_to_cstring
(
status
,
errormsg
,
sizeof
(
errormsg
));
throw
FormatRuntimeError
(
"unable to start audio output: %s"
,
errormsg
);
}
}
s
tatic
s
ize_t
osx_output_play
(
AudioOutput
*
ao
,
const
void
*
chunk
,
size_t
size
)
size_t
OSXOutput
::
Play
(
const
void
*
chunk
,
size_t
size
)
{
OSXOutput
*
od
=
(
OSXOutput
*
)
ao
;
return
od
->
ring_buffer
->
push
((
uint8_t
*
)
chunk
,
size
);
return
ring_buffer
->
push
((
uint8_t
*
)
chunk
,
size
);
}
st
atic
st
d
::
chrono
::
steady_clock
::
duration
osx_output_delay
(
AudioOutput
*
ao
)
noexcept
std
::
chrono
::
steady_clock
::
duration
OSXOutput
::
Delay
()
const
noexcept
{
OSXOutput
*
od
=
(
OSXOutput
*
)
ao
;
return
od
->
ring_buffer
->
write_available
()
return
ring_buffer
->
write_available
()
?
std
::
chrono
::
steady_clock
::
duration
::
zero
()
:
std
::
chrono
::
milliseconds
(
25
);
}
...
...
@@ -681,17 +672,6 @@ osx_output_delay(AudioOutput *ao) noexcept
const
struct
AudioOutputPlugin
osx_output_plugin
=
{
"osx"
,
osx_output_test_default_device
,
osx_output_init
,
osx_output_finish
,
osx_output_enable
,
osx_output_disable
,
osx_output_open
,
osx_output_close
,
osx_output_delay
,
nullptr
,
osx_output_play
,
nullptr
,
nullptr
,
nullptr
,
&
OSXOutput
::
Create
,
nullptr
,
};
src/output/plugins/OpenALOutputPlugin.cxx
View file @
31bad5f7
...
...
@@ -20,7 +20,6 @@
#include "config.h"
#include "OpenALOutputPlugin.hxx"
#include "../OutputAPI.hxx"
#include "../Wrapper.hxx"
#include "util/RuntimeError.hxx"
#include <unistd.h>
...
...
@@ -33,14 +32,10 @@
#include <OpenAL/alc.h>
#endif
class
OpenALOutput
{
friend
struct
AudioOutputWrapper
<
OpenALOutput
>
;
class
OpenALOutput
final
:
AudioOutput
{
/* should be enough for buffer size = 2048 */
static
constexpr
unsigned
NUM_BUFFERS
=
16
;
AudioOutput
base
;
const
char
*
device_name
;
ALCdevice
*
device
;
ALCcontext
*
context
;
...
...
@@ -52,14 +47,18 @@ class OpenALOutput {
OpenALOutput
(
const
ConfigBlock
&
block
);
static
OpenALOutput
*
Create
(
EventLoop
&
event_loop
,
const
ConfigBlock
&
block
);
public
:
static
AudioOutput
*
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
return
new
OpenALOutput
(
block
);
}
void
Open
(
AudioFormat
&
audio_format
);
void
Close
();
private
:
void
Open
(
AudioFormat
&
audio_format
)
override
;
void
Close
()
noexcept
override
;
gcc_pure
std
::
chrono
::
steady_clock
::
duration
Delay
()
const
noexcept
{
std
::
chrono
::
steady_clock
::
duration
Delay
()
const
noexcept
override
{
return
filled
<
NUM_BUFFERS
||
HasProcessed
()
?
std
::
chrono
::
steady_clock
::
duration
::
zero
()
/* we don't know exactly how long we must wait
...
...
@@ -68,9 +67,9 @@ class OpenALOutput {
:
std
::
chrono
::
milliseconds
(
50
);
}
size_t
Play
(
const
void
*
chunk
,
size_t
size
);
size_t
Play
(
const
void
*
chunk
,
size_t
size
)
override
;
void
Cancel
();
void
Cancel
()
noexcept
override
;
private
:
gcc_pure
...
...
@@ -138,7 +137,7 @@ OpenALOutput::SetupContext()
}
OpenALOutput
::
OpenALOutput
(
const
ConfigBlock
&
block
)
:
base
(
openal_output_plugin
),
:
AudioOutput
(
0
),
device_name
(
block
.
GetBlockValue
(
"device"
))
{
if
(
device_name
==
nullptr
)
...
...
@@ -146,13 +145,7 @@ OpenALOutput::OpenALOutput(const ConfigBlock &block)
ALC_DEFAULT_DEVICE_SPECIFIER
);
}
inline
OpenALOutput
*
OpenALOutput
::
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
return
new
OpenALOutput
(
block
);
}
inline
void
void
OpenALOutput
::
Open
(
AudioFormat
&
audio_format
)
{
format
=
openal_audio_format
(
audio_format
);
...
...
@@ -176,8 +169,8 @@ OpenALOutput::Open(AudioFormat &audio_format)
frequency
=
audio_format
.
sample_rate
;
}
inline
void
OpenALOutput
::
Close
()
void
OpenALOutput
::
Close
()
noexcept
{
alcMakeContextCurrent
(
context
);
alDeleteSources
(
1
,
&
source
);
...
...
@@ -186,7 +179,7 @@ OpenALOutput::Close()
alcCloseDevice
(
device
);
}
inline
size_t
size_t
OpenALOutput
::
Play
(
const
void
*
chunk
,
size_t
size
)
{
if
(
alcGetCurrentContext
()
!=
context
)
...
...
@@ -214,8 +207,8 @@ OpenALOutput::Play(const void *chunk, size_t size)
return
size
;
}
inline
void
OpenALOutput
::
Cancel
()
void
OpenALOutput
::
Cancel
()
noexcept
{
filled
=
0
;
alcMakeContextCurrent
(
context
);
...
...
@@ -226,22 +219,9 @@ OpenALOutput::Cancel()
filled
=
0
;
}
typedef
AudioOutputWrapper
<
OpenALOutput
>
Wrapper
;
const
struct
AudioOutputPlugin
openal_output_plugin
=
{
"openal"
,
nullptr
,
&
Wrapper
::
Init
,
&
Wrapper
::
Finish
,
nullptr
,
nullptr
,
&
Wrapper
::
Open
,
&
Wrapper
::
Close
,
&
Wrapper
::
Delay
,
nullptr
,
&
Wrapper
::
Play
,
nullptr
,
&
Wrapper
::
Cancel
,
nullptr
,
OpenALOutput
::
Create
,
nullptr
,
};
src/output/plugins/OssOutputPlugin.cxx
View file @
31bad5f7
...
...
@@ -20,7 +20,6 @@
#include "config.h"
#include "OssOutputPlugin.hxx"
#include "../OutputAPI.hxx"
#include "../Wrapper.hxx"
#include "mixer/MixerList.hxx"
#include "system/fd_util.h"
#include "system/Error.hxx"
...
...
@@ -60,11 +59,7 @@
#include "util/Manual.hxx"
#endif
class
OssOutput
{
friend
struct
AudioOutputWrapper
<
OssOutput
>
;
AudioOutput
base
;
class
OssOutput
final
:
AudioOutput
{
#ifdef AFMT_S24_PACKED
Manual
<
PcmExport
>
pcm_export
;
#endif
...
...
@@ -84,32 +79,38 @@ class OssOutput {
*/
int
oss_format
;
#ifdef AFMT_S24_PACKED
static
constexpr
unsigned
oss_flags
=
FLAG_ENABLE_DISABLE
;
#else
static
constexpr
unsigned
oss_flags
=
0
;
#endif
public
:
explicit
OssOutput
(
const
char
*
_device
=
nullptr
)
:
base
(
oss_output_plugin
),
:
AudioOutput
(
oss_flags
),
fd
(
-
1
),
device
(
_device
)
{}
static
Oss
Output
*
Create
(
EventLoop
&
event_loop
,
const
ConfigBlock
&
block
);
static
Audio
Output
*
Create
(
EventLoop
&
event_loop
,
const
ConfigBlock
&
block
);
#ifdef AFMT_S24_PACKED
void
Enable
()
{
void
Enable
()
override
{
pcm_export
.
Construct
();
}
void
Disable
()
{
void
Disable
()
noexcept
override
{
pcm_export
.
Destruct
();
}
#endif
void
Open
(
AudioFormat
&
audio_format
);
void
Open
(
AudioFormat
&
audio_format
)
override
;
void
Close
()
{
void
Close
()
noexcept
override
{
DoClose
();
}
size_t
Play
(
const
void
*
chunk
,
size_t
size
);
void
Cancel
();
size_t
Play
(
const
void
*
chunk
,
size_t
size
)
override
;
void
Cancel
()
noexcept
override
;
private
:
/**
...
...
@@ -225,7 +226,7 @@ oss_open_default()
throw
std
::
runtime_error
(
"error trying to open default OSS device"
);
}
inline
Oss
Output
*
Audio
Output
*
OssOutput
::
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
const
char
*
device
=
block
.
GetBlockValue
(
"device"
);
...
...
@@ -637,7 +638,7 @@ try {
throw
;
}
inline
void
void
OssOutput
::
Open
(
AudioFormat
&
_audio_format
)
try
{
fd
=
open_cloexec
(
device
,
O_WRONLY
,
0
);
...
...
@@ -652,8 +653,8 @@ try {
throw
;
}
inline
void
OssOutput
::
Cancel
()
void
OssOutput
::
Cancel
()
noexcept
{
if
(
fd
>=
0
)
{
ioctl
(
fd
,
SNDCTL_DSP_RESET
,
0
);
...
...
@@ -665,7 +666,7 @@ OssOutput::Cancel()
#endif
}
inline
size_t
size_t
OssOutput
::
Play
(
const
void
*
chunk
,
size_t
size
)
{
ssize_t
ret
;
...
...
@@ -698,28 +699,9 @@ OssOutput::Play(const void *chunk, size_t size)
}
}
typedef
AudioOutputWrapper
<
OssOutput
>
Wrapper
;
const
struct
AudioOutputPlugin
oss_output_plugin
=
{
"oss"
,
oss_output_test_default_device
,
&
Wrapper
::
Init
,
&
Wrapper
::
Finish
,
#ifdef AFMT_S24_PACKED
&
Wrapper
::
Enable
,
&
Wrapper
::
Disable
,
#else
nullptr
,
nullptr
,
#endif
&
Wrapper
::
Open
,
&
Wrapper
::
Close
,
nullptr
,
nullptr
,
&
Wrapper
::
Play
,
nullptr
,
&
Wrapper
::
Cancel
,
nullptr
,
OssOutput
::
Create
,
&
oss_mixer_plugin
,
};
src/output/plugins/PipeOutputPlugin.cxx
View file @
31bad5f7
...
...
@@ -20,7 +20,6 @@
#include "config.h"
#include "PipeOutputPlugin.hxx"
#include "../OutputAPI.hxx"
#include "../Wrapper.hxx"
#include "system/Error.hxx"
#include <string>
...
...
@@ -28,43 +27,36 @@
#include <stdio.h>
class
PipeOutput
{
friend
struct
AudioOutputWrapper
<
PipeOutput
>
;
AudioOutput
base
;
class
PipeOutput
final
:
AudioOutput
{
const
std
::
string
cmd
;
FILE
*
fh
;
PipeOutput
(
const
ConfigBlock
&
block
);
public
:
static
PipeOutput
*
Create
(
EventLoop
&
event_loop
,
const
ConfigBlock
&
block
);
static
AudioOutput
*
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
return
new
PipeOutput
(
block
);
}
void
Open
(
AudioFormat
&
audio_format
);
private
:
void
Open
(
AudioFormat
&
audio_format
)
override
;
void
Close
()
{
void
Close
()
noexcept
override
{
pclose
(
fh
);
}
size_t
Play
(
const
void
*
chunk
,
size_t
size
);
size_t
Play
(
const
void
*
chunk
,
size_t
size
)
override
;
};
PipeOutput
::
PipeOutput
(
const
ConfigBlock
&
block
)
:
base
(
pipe_output_plugin
),
:
AudioOutput
(
0
),
cmd
(
block
.
GetBlockValue
(
"command"
,
""
))
{
if
(
cmd
.
empty
())
throw
std
::
runtime_error
(
"No
\"
command
\"
parameter specified"
);
}
inline
PipeOutput
*
PipeOutput
::
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
return
new
PipeOutput
(
block
);
}
inline
void
PipeOutput
::
Open
(
gcc_unused
AudioFormat
&
audio_format
)
{
...
...
@@ -83,22 +75,9 @@ PipeOutput::Play(const void *chunk, size_t size)
return
nbytes
;
}
typedef
AudioOutputWrapper
<
PipeOutput
>
Wrapper
;
const
struct
AudioOutputPlugin
pipe_output_plugin
=
{
"pipe"
,
nullptr
,
&
Wrapper
::
Init
,
&
Wrapper
::
Finish
,
nullptr
,
nullptr
,
&
Wrapper
::
Open
,
&
Wrapper
::
Close
,
nullptr
,
nullptr
,
&
Wrapper
::
Play
,
nullptr
,
nullptr
,
nullptr
,
&
PipeOutput
::
Create
,
nullptr
,
};
src/output/plugins/PulseOutputPlugin.cxx
View file @
31bad5f7
...
...
@@ -24,7 +24,6 @@
#include "lib/pulse/LogError.hxx"
#include "lib/pulse/LockGuard.hxx"
#include "../OutputAPI.hxx"
#include "../Wrapper.hxx"
#include "mixer/MixerList.hxx"
#include "mixer/plugins/PulseMixerPlugin.hxx"
#include "Log.hxx"
...
...
@@ -44,11 +43,7 @@
#define MPD_PULSE_NAME "Music Player Daemon"
class
PulseOutput
{
friend
struct
AudioOutputWrapper
<
PulseOutput
>
;
AudioOutput
base
;
class
PulseOutput
final
:
AudioOutput
{
const
char
*
name
;
const
char
*
server
;
const
char
*
sink
;
...
...
@@ -94,19 +89,21 @@ public:
static
bool
TestDefaultDevice
();
static
PulseOutput
*
Create
(
EventLoop
&
event_loop
,
const
ConfigBlock
&
block
);
static
AudioOutput
*
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
return
new
PulseOutput
(
block
);
}
void
Enable
();
void
Disable
();
void
Enable
()
override
;
void
Disable
()
noexcept
override
;
void
Open
(
AudioFormat
&
audio_format
);
void
Close
();
void
Open
(
AudioFormat
&
audio_format
)
override
;
void
Close
()
noexcept
override
;
std
::
chrono
::
steady_clock
::
duration
Delay
()
noexcept
;
size_t
Play
(
const
void
*
chunk
,
size_t
size
);
void
Cancel
();
bool
Pause
();
std
::
chrono
::
steady_clock
::
duration
Delay
()
const
noexcept
override
;
size_t
Play
(
const
void
*
chunk
,
size_t
size
)
override
;
void
Cancel
()
noexcept
override
;
bool
Pause
()
noexcept
override
;
private
:
/**
...
...
@@ -179,7 +176,7 @@ private:
};
PulseOutput
::
PulseOutput
(
const
ConfigBlock
&
block
)
:
base
(
pulse_output_plugin
),
:
AudioOutput
(
FLAG_ENABLE_DISABLE
|
FLAG_PAUSE
),
name
(
block
.
GetBlockValue
(
"name"
,
"mpd_pulse"
)),
server
(
block
.
GetBlockValue
(
"server"
)),
sink
(
block
.
GetBlockValue
(
"sink"
))
...
...
@@ -416,13 +413,7 @@ PulseOutput::SetupContext()
}
}
PulseOutput
*
PulseOutput
::
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
return
new
PulseOutput
(
block
);
}
inline
void
void
PulseOutput
::
Enable
()
{
assert
(
mainloop
==
nullptr
);
...
...
@@ -458,8 +449,8 @@ PulseOutput::Enable()
pa_threaded_mainloop_unlock
(
mainloop
);
}
inline
void
PulseOutput
::
Disable
()
void
PulseOutput
::
Disable
()
noexcept
{
assert
(
mainloop
!=
nullptr
);
...
...
@@ -607,7 +598,7 @@ PulseOutput::SetupStream(const pa_sample_spec &ss)
pulse_output_stream_write_cb
,
this
);
}
inline
void
void
PulseOutput
::
Open
(
AudioFormat
&
audio_format
)
{
assert
(
mainloop
!=
nullptr
);
...
...
@@ -680,8 +671,8 @@ PulseOutput::Open(AudioFormat &audio_format)
pause
=
false
;
}
inline
void
PulseOutput
::
Close
()
void
PulseOutput
::
Close
()
noexcept
{
assert
(
mainloop
!=
nullptr
);
...
...
@@ -744,8 +735,8 @@ PulseOutput::StreamPause(bool _pause)
"pa_stream_cork() has failed"
);
}
inline
std
::
chrono
::
steady_clock
::
duration
PulseOutput
::
Delay
()
noexcept
std
::
chrono
::
steady_clock
::
duration
PulseOutput
::
Delay
()
const
noexcept
{
Pulse
::
LockGuard
lock
(
mainloop
);
...
...
@@ -758,7 +749,7 @@ PulseOutput::Delay() noexcept
return
result
;
}
inline
size_t
size_t
PulseOutput
::
Play
(
const
void
*
chunk
,
size_t
size
)
{
assert
(
mainloop
!=
nullptr
);
...
...
@@ -807,8 +798,8 @@ PulseOutput::Play(const void *chunk, size_t size)
return
size
;
}
inline
void
PulseOutput
::
Cancel
()
void
PulseOutput
::
Cancel
()
noexcept
{
assert
(
mainloop
!=
nullptr
);
assert
(
stream
!=
nullptr
);
...
...
@@ -834,8 +825,8 @@ PulseOutput::Cancel()
pulse_wait_for_operation
(
mainloop
,
o
);
}
inline
bool
PulseOutput
::
Pause
()
bool
PulseOutput
::
Pause
()
noexcept
{
assert
(
mainloop
!=
nullptr
);
assert
(
stream
!=
nullptr
);
...
...
@@ -875,23 +866,9 @@ pulse_output_test_default_device(void)
return
PulseOutput
::
TestDefaultDevice
();
}
typedef
AudioOutputWrapper
<
PulseOutput
>
Wrapper
;
const
struct
AudioOutputPlugin
pulse_output_plugin
=
{
"pulse"
,
pulse_output_test_default_device
,
&
Wrapper
::
Init
,
&
Wrapper
::
Finish
,
&
Wrapper
::
Enable
,
&
Wrapper
::
Disable
,
&
Wrapper
::
Open
,
&
Wrapper
::
Close
,
&
Wrapper
::
Delay
,
nullptr
,
&
Wrapper
::
Play
,
nullptr
,
&
Wrapper
::
Cancel
,
&
Wrapper
::
Pause
,
PulseOutput
::
Create
,
&
pulse_mixer_plugin
,
};
src/output/plugins/RecorderOutputPlugin.cxx
View file @
31bad5f7
...
...
@@ -20,7 +20,6 @@
#include "config.h"
#include "RecorderOutputPlugin.hxx"
#include "../OutputAPI.hxx"
#include "../Wrapper.hxx"
#include "tag/Format.hxx"
#include "encoder/ToOutputStream.hxx"
#include "encoder/EncoderInterface.hxx"
...
...
@@ -42,11 +41,7 @@
static
constexpr
Domain
recorder_domain
(
"recorder"
);
class
RecorderOutput
{
friend
struct
AudioOutputWrapper
<
RecorderOutput
>
;
AudioOutput
base
;
class
RecorderOutput
final
:
AudioOutput
{
/**
* The configured encoder plugin.
*/
...
...
@@ -81,20 +76,23 @@ class RecorderOutput {
delete
prepared_encoder
;
}
static
RecorderOutput
*
Create
(
EventLoop
&
event_loop
,
const
ConfigBlock
&
block
);
public
:
static
AudioOutput
*
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
return
new
RecorderOutput
(
block
);
}
void
Open
(
AudioFormat
&
audio_format
);
void
Close
();
private
:
void
Open
(
AudioFormat
&
audio_format
)
override
;
void
Close
()
noexcept
override
;
/**
* Writes pending data from the encoder to the output file.
*/
void
EncoderToFile
();
void
SendTag
(
const
Tag
&
tag
);
void
SendTag
(
const
Tag
&
tag
)
override
;
size_t
Play
(
const
void
*
chunk
,
size_t
size
);
size_t
Play
(
const
void
*
chunk
,
size_t
size
)
override
;
private
:
gcc_pure
...
...
@@ -114,7 +112,7 @@ private:
};
RecorderOutput
::
RecorderOutput
(
const
ConfigBlock
&
block
)
:
base
(
recorder_output_plugin
)
:
AudioOutput
(
0
)
{
/* read configuration */
...
...
@@ -141,12 +139,6 @@ RecorderOutput::RecorderOutput(const ConfigBlock &block)
prepared_encoder
=
encoder_init
(
*
encoder_plugin
,
block
);
}
RecorderOutput
*
RecorderOutput
::
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
return
new
RecorderOutput
(
block
);
}
inline
void
RecorderOutput
::
EncoderToFile
()
{
...
...
@@ -155,7 +147,7 @@ RecorderOutput::EncoderToFile()
EncoderToOutputStream
(
*
file
,
*
encoder
);
}
inline
void
void
RecorderOutput
::
Open
(
AudioFormat
&
audio_format
)
{
/* create the output file */
...
...
@@ -227,8 +219,8 @@ RecorderOutput::Commit()
delete
file
;
}
inline
void
RecorderOutput
::
Close
()
void
RecorderOutput
::
Close
()
noexcept
{
if
(
file
==
nullptr
)
{
/* not currently encoding to a file; nothing needs to
...
...
@@ -305,7 +297,7 @@ RecorderOutput::ReopenFormat(AllocatedPath &&new_path)
path
.
ToUTF8
().
c_str
());
}
inline
void
void
RecorderOutput
::
SendTag
(
const
Tag
&
tag
)
{
if
(
HasDynamicPath
())
{
...
...
@@ -347,7 +339,7 @@ RecorderOutput::SendTag(const Tag &tag)
encoder
->
SendTag
(
tag
);
}
inline
size_t
size_t
RecorderOutput
::
Play
(
const
void
*
chunk
,
size_t
size
)
{
if
(
file
==
nullptr
)
{
...
...
@@ -365,22 +357,9 @@ RecorderOutput::Play(const void *chunk, size_t size)
return
size
;
}
typedef
AudioOutputWrapper
<
RecorderOutput
>
Wrapper
;
const
struct
AudioOutputPlugin
recorder_output_plugin
=
{
"recorder"
,
nullptr
,
&
Wrapper
::
Init
,
&
Wrapper
::
Finish
,
nullptr
,
nullptr
,
&
Wrapper
::
Open
,
&
Wrapper
::
Close
,
nullptr
,
&
Wrapper
::
SendTag
,
&
Wrapper
::
Play
,
nullptr
,
nullptr
,
nullptr
,
&
RecorderOutput
::
Create
,
nullptr
,
};
src/output/plugins/RoarOutputPlugin.cxx
View file @
31bad5f7
...
...
@@ -21,7 +21,6 @@
#include "config.h"
#include "RoarOutputPlugin.hxx"
#include "../OutputAPI.hxx"
#include "../Wrapper.hxx"
#include "mixer/MixerList.hxx"
#include "thread/Mutex.hxx"
#include "util/Domain.hxx"
...
...
@@ -36,11 +35,7 @@
#include <roaraudio.h>
#undef new
class
RoarOutput
{
friend
struct
AudioOutputWrapper
<
RoarOutput
>
;
AudioOutput
base
;
class
RoarOutput
final
:
AudioOutput
{
const
std
::
string
host
,
name
;
roar_vs_t
*
vss
;
...
...
@@ -54,23 +49,20 @@ class RoarOutput {
public
:
RoarOutput
(
const
ConfigBlock
&
block
);
operator
AudioOutput
*
()
{
return
&
base
;
}
static
RoarOutput
*
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
static
AudioOutput
*
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
return
new
RoarOutput
(
block
);
}
void
Open
(
AudioFormat
&
audio_format
);
void
Close
();
void
SendTag
(
const
Tag
&
tag
);
size_t
Play
(
const
void
*
chunk
,
size_t
size
);
void
Cancel
();
int
GetVolume
()
const
;
void
SetVolume
(
unsigned
volume
);
private
:
void
Open
(
AudioFormat
&
audio_format
)
override
;
void
Close
()
noexcept
override
;
void
SendTag
(
const
Tag
&
tag
)
override
;
size_t
Play
(
const
void
*
chunk
,
size_t
size
)
override
;
void
Cancel
()
noexcept
override
;
};
static
constexpr
Domain
roar_output_domain
(
"roar_output"
);
...
...
@@ -86,7 +78,7 @@ GetConfiguredRole(const ConfigBlock &block) noexcept
}
RoarOutput
::
RoarOutput
(
const
ConfigBlock
&
block
)
:
base
(
roar_output_plugin
),
:
AudioOutput
(
0
),
host
(
block
.
GetBlockValue
(
"server"
,
""
)),
name
(
block
.
GetBlockValue
(
"name"
,
"MPD"
)),
role
(
GetConfiguredRole
(
block
))
...
...
@@ -172,7 +164,7 @@ roar_use_audio_format(struct roar_audio_info *info,
}
}
inline
void
void
RoarOutput
::
Open
(
AudioFormat
&
audio_format
)
{
const
std
::
lock_guard
<
Mutex
>
protect
(
mutex
);
...
...
@@ -196,8 +188,8 @@ RoarOutput::Open(AudioFormat &audio_format)
alive
=
true
;
}
inline
void
RoarOutput
::
Close
()
void
RoarOutput
::
Close
()
noexcept
{
const
std
::
lock_guard
<
Mutex
>
protect
(
mutex
);
...
...
@@ -209,8 +201,8 @@ RoarOutput::Close()
roar_disconnect
(
&
con
);
}
inline
void
RoarOutput
::
Cancel
()
void
RoarOutput
::
Cancel
()
noexcept
{
const
std
::
lock_guard
<
Mutex
>
protect
(
mutex
);
...
...
@@ -237,7 +229,7 @@ RoarOutput::Cancel()
alive
=
true
;
}
inline
size_t
size_t
RoarOutput
::
Play
(
const
void
*
chunk
,
size_t
size
)
{
if
(
vss
==
nullptr
)
...
...
@@ -296,7 +288,7 @@ roar_tag_convert(TagType type, bool *is_uuid)
}
}
inline
void
void
RoarOutput
::
SendTag
(
const
Tag
&
tag
)
{
if
(
vss
==
nullptr
)
...
...
@@ -344,22 +336,9 @@ RoarOutput::SendTag(const Tag &tag)
roar_vs_meta
(
vss
,
vals
,
cnt
,
&
(
err
));
}
typedef
AudioOutputWrapper
<
RoarOutput
>
Wrapper
;
const
struct
AudioOutputPlugin
roar_output_plugin
=
{
"roar"
,
nullptr
,
&
Wrapper
::
Init
,
&
Wrapper
::
Finish
,
nullptr
,
nullptr
,
&
Wrapper
::
Open
,
&
Wrapper
::
Close
,
nullptr
,
&
Wrapper
::
SendTag
,
&
Wrapper
::
Play
,
nullptr
,
&
Wrapper
::
Cancel
,
nullptr
,
&
RoarOutput
::
Create
,
&
roar_mixer_plugin
,
};
src/output/plugins/ShoutOutputPlugin.cxx
View file @
31bad5f7
...
...
@@ -20,7 +20,6 @@
#include "config.h"
#include "ShoutOutputPlugin.hxx"
#include "../OutputAPI.hxx"
#include "../Wrapper.hxx"
#include "encoder/EncoderInterface.hxx"
#include "encoder/EncoderPlugin.hxx"
#include "encoder/EncoderList.hxx"
...
...
@@ -39,9 +38,7 @@
static
constexpr
unsigned
DEFAULT_CONN_TIMEOUT
=
2
;
struct
ShoutOutput
final
{
AudioOutput
base
;
struct
ShoutOutput
final
:
AudioOutput
{
shout_t
*
shout_conn
;
shout_metadata_t
*
shout_meta
;
...
...
@@ -58,17 +55,17 @@ struct ShoutOutput final {
explicit
ShoutOutput
(
const
ConfigBlock
&
block
);
~
ShoutOutput
();
static
Shout
Output
*
Create
(
EventLoop
&
event_loop
,
static
Audio
Output
*
Create
(
EventLoop
&
event_loop
,
const
ConfigBlock
&
block
);
void
Open
(
AudioFormat
&
audio_format
);
void
Close
();
void
Open
(
AudioFormat
&
audio_format
)
override
;
void
Close
()
noexcept
override
;
std
::
chrono
::
steady_clock
::
duration
Delay
()
const
noexcept
;
void
SendTag
(
const
Tag
&
tag
);
size_t
Play
(
const
void
*
chunk
,
size_t
size
);
void
Cancel
();
bool
Pause
();
std
::
chrono
::
steady_clock
::
duration
Delay
()
const
noexcept
override
;
void
SendTag
(
const
Tag
&
tag
)
override
;
size_t
Play
(
const
void
*
chunk
,
size_t
size
)
override
;
void
Cancel
()
noexcept
override
;
bool
Pause
()
noexcept
override
;
private
:
void
WritePage
();
...
...
@@ -113,11 +110,11 @@ ShoutSetAudioInfo(shout_t *shout_conn, const AudioFormat &audio_format)
}
ShoutOutput
::
ShoutOutput
(
const
ConfigBlock
&
block
)
:
base
(
shout_output_plugin
),
:
AudioOutput
(
FLAG_PAUSE
),
shout_conn
(
shout_new
()),
shout_meta
(
shout_metadata_new
())
{
base
.
NeedFullyDefinedAudioFormat
();
NeedFullyDefinedAudioFormat
();
const
char
*
host
=
require_block_string
(
block
,
"host"
);
const
char
*
mount
=
require_block_string
(
block
,
"mount"
);
...
...
@@ -250,7 +247,7 @@ ShoutOutput::~ShoutOutput()
delete
prepared_encoder
;
}
Shout
Output
*
Audio
Output
*
ShoutOutput
::
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
if
(
shout_init_count
==
0
)
...
...
@@ -306,7 +303,7 @@ ShoutOutput::WritePage()
}
void
ShoutOutput
::
Close
()
ShoutOutput
::
Close
()
noexcept
{
try
{
encoder
->
End
();
...
...
@@ -326,7 +323,7 @@ ShoutOutput::Close()
}
void
ShoutOutput
::
Cancel
()
ShoutOutput
::
Cancel
()
noexcept
{
/* needs to be implemented for shout */
}
...
...
@@ -381,7 +378,7 @@ ShoutOutput::Play(const void *chunk, size_t size)
}
bool
ShoutOutput
::
Pause
()
ShoutOutput
::
Pause
()
noexcept
{
static
char
silence
[
1020
];
...
...
@@ -446,22 +443,9 @@ ShoutOutput::SendTag(const Tag &tag)
WritePage
();
}
typedef
AudioOutputWrapper
<
ShoutOutput
>
Wrapper
;
const
struct
AudioOutputPlugin
shout_output_plugin
=
{
"shout"
,
nullptr
,
&
Wrapper
::
Init
,
&
Wrapper
::
Finish
,
nullptr
,
nullptr
,
&
Wrapper
::
Open
,
&
Wrapper
::
Close
,
&
Wrapper
::
Delay
,
&
Wrapper
::
SendTag
,
&
Wrapper
::
Play
,
nullptr
,
&
Wrapper
::
Cancel
,
&
Wrapper
::
Pause
,
&
ShoutOutput
::
Create
,
nullptr
,
};
src/output/plugins/SndioOutputPlugin.cxx
View file @
31bad5f7
...
...
@@ -20,7 +20,6 @@
#include "config.h"
#include "SndioOutputPlugin.hxx"
#include "../OutputAPI.hxx"
#include "../Wrapper.hxx"
#include "util/Domain.hxx"
#include "Log.hxx"
...
...
@@ -45,9 +44,7 @@ static constexpr unsigned MPD_SNDIO_BUFFER_TIME_MS = 250;
static
constexpr
Domain
sndio_output_domain
(
"sndio_output"
);
class
SndioOutput
{
friend
struct
AudioOutputWrapper
<
SndioOutput
>
;
AudioOutput
base
;
class
SndioOutput
final
:
AudioOutput
{
const
char
*
const
device
;
const
unsigned
buffer_time
;
/* in ms */
struct
sio_hdl
*
sio_hdl
;
...
...
@@ -55,29 +52,25 @@ class SndioOutput {
public
:
SndioOutput
(
const
ConfigBlock
&
block
);
static
SndioOutput
*
Create
(
EventLoop
&
event_loop
,
const
ConfigBlock
&
block
);
static
AudioOutput
*
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
return
new
SndioOutput
(
block
);
}
void
Open
(
AudioFormat
&
audio_format
);
void
Close
()
;
size_t
Play
(
const
void
*
chunk
,
size_t
size
)
;
void
Cancel
()
;
private
:
void
Open
(
AudioFormat
&
audio_format
)
override
;
void
Close
()
noexcept
override
;
size_t
Play
(
const
void
*
chunk
,
size_t
size
)
override
;
};
SndioOutput
::
SndioOutput
(
const
ConfigBlock
&
block
)
:
base
(
sndio_output_plugin
),
:
AudioOutput
(
0
),
device
(
block
.
GetBlockValue
(
"device"
,
SIO_DEVANY
)),
buffer_time
(
block
.
GetBlockValue
(
"buffer_time"
,
MPD_SNDIO_BUFFER_TIME_MS
))
{
}
SndioOutput
*
SndioOutput
::
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
return
new
SndioOutput
(
block
);
}
static
bool
sndio_test_default_device
()
{
...
...
@@ -154,7 +147,7 @@ SndioOutput::Open(AudioFormat &audio_format)
}
void
SndioOutput
::
Close
()
SndioOutput
::
Close
()
noexcept
{
sio_close
(
sio_hdl
);
}
...
...
@@ -170,22 +163,9 @@ SndioOutput::Play(const void *chunk, size_t size)
return
n
;
}
typedef
AudioOutputWrapper
<
SndioOutput
>
Wrapper
;
const
struct
AudioOutputPlugin
sndio_output_plugin
=
{
"sndio"
,
sndio_test_default_device
,
&
Wrapper
::
Init
,
&
Wrapper
::
Finish
,
nullptr
,
nullptr
,
&
Wrapper
::
Open
,
&
Wrapper
::
Close
,
nullptr
,
nullptr
,
&
Wrapper
::
Play
,
nullptr
,
nullptr
,
nullptr
,
&
SndioOutput
::
Create
,
nullptr
,
};
src/output/plugins/SolarisOutputPlugin.cxx
View file @
31bad5f7
...
...
@@ -20,7 +20,6 @@
#include "config.h"
#include "SolarisOutputPlugin.hxx"
#include "../OutputAPI.hxx"
#include "../Wrapper.hxx"
#include "system/FileDescriptor.hxx"
#include "system/Error.hxx"
...
...
@@ -50,30 +49,27 @@ struct audio_info {
#endif
class
SolarisOutput
{
friend
struct
AudioOutputWrapper
<
SolarisOutput
>
;
AudioOutput
base
;
class
SolarisOutput
final
:
AudioOutput
{
/* configuration */
const
char
*
const
device
;
FileDescriptor
fd
;
explicit
SolarisOutput
(
const
ConfigBlock
&
block
)
:
base
(
solaris_output_plugin
),
:
AudioOutput
(
0
),
device
(
block
.
GetBlockValue
(
"device"
,
"/dev/audio"
))
{}
public
:
static
Solaris
Output
*
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
static
Audio
Output
*
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
return
new
SolarisOutput
(
block
);
}
void
Open
(
AudioFormat
&
audio_format
);
void
Close
();
private
:
void
Open
(
AudioFormat
&
audio_format
)
override
;
void
Close
()
noexcept
override
;
size_t
Play
(
const
void
*
chunk
,
size_t
size
);
void
Cancel
();
size_t
Play
(
const
void
*
chunk
,
size_t
size
)
override
;
void
Cancel
()
noexcept
override
;
};
static
bool
...
...
@@ -128,7 +124,7 @@ SolarisOutput::Open(AudioFormat &audio_format)
}
void
SolarisOutput
::
Close
()
SolarisOutput
::
Close
()
noexcept
{
fd
.
Close
();
}
...
...
@@ -144,27 +140,14 @@ SolarisOutput::Play(const void *chunk, size_t size)
}
void
SolarisOutput
::
Cancel
()
SolarisOutput
::
Cancel
()
noexcept
{
ioctl
(
fd
.
Get
(),
I_FLUSH
);
}
typedef
AudioOutputWrapper
<
SolarisOutput
>
Wrapper
;
const
struct
AudioOutputPlugin
solaris_output_plugin
=
{
"solaris"
,
solaris_output_test_default_device
,
&
Wrapper
::
Init
,
&
Wrapper
::
Finish
,
nullptr
,
nullptr
,
&
Wrapper
::
Open
,
&
Wrapper
::
Close
,
nullptr
,
nullptr
,
&
Wrapper
::
Play
,
nullptr
,
&
Wrapper
::
Cancel
,
nullptr
,
&
SolarisOutput
::
Create
,
nullptr
,
};
src/output/plugins/WinmmOutputPlugin.cxx
View file @
31bad5f7
...
...
@@ -20,7 +20,6 @@
#include "config.h"
#include "WinmmOutputPlugin.hxx"
#include "../OutputAPI.hxx"
#include "../Wrapper.hxx"
#include "pcm/PcmBuffer.hxx"
#include "mixer/MixerList.hxx"
#include "fs/AllocatedPath.hxx"
...
...
@@ -39,11 +38,7 @@ struct WinmmBuffer {
WAVEHDR
hdr
;
};
class
WinmmOutput
{
friend
struct
AudioOutputWrapper
<
WinmmOutput
>
;
AudioOutput
base
;
class
WinmmOutput
final
:
AudioOutput
{
const
UINT
device_id
;
HWAVEOUT
handle
;
...
...
@@ -63,16 +58,17 @@ public:
return
handle
;
}
static
Winmm
Output
*
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
static
Audio
Output
*
Create
(
EventLoop
&
,
const
ConfigBlock
&
block
)
{
return
new
WinmmOutput
(
block
);
}
void
Open
(
AudioFormat
&
audio_format
);
void
Close
();
private
:
void
Open
(
AudioFormat
&
audio_format
)
override
;
void
Close
()
noexcept
override
;
size_t
Play
(
const
void
*
chunk
,
size_t
size
);
void
Drain
();
void
Cancel
();
size_t
Play
(
const
void
*
chunk
,
size_t
size
)
override
;
void
Drain
()
override
;
void
Cancel
()
noexcept
override
;
private
:
/**
...
...
@@ -82,7 +78,7 @@ private:
void
DrainAllBuffers
();
void
Stop
();
void
Stop
()
noexcept
;
};
...
...
@@ -148,7 +144,7 @@ get_device_id(const char *device_name)
}
WinmmOutput
::
WinmmOutput
(
const
ConfigBlock
&
block
)
:
base
(
winmm_output_plugin
),
:
AudioOutput
(
0
),
device_id
(
get_device_id
(
block
.
GetBlockValue
(
"device"
)))
{
}
...
...
@@ -202,7 +198,7 @@ WinmmOutput::Open(AudioFormat &audio_format)
}
void
WinmmOutput
::
Close
()
WinmmOutput
::
Close
()
noexcept
{
for
(
auto
&
i
:
buffers
)
i
.
buffer
.
Clear
();
...
...
@@ -291,7 +287,7 @@ WinmmOutput::DrainAllBuffers()
}
void
WinmmOutput
::
Stop
()
WinmmOutput
::
Stop
()
noexcept
{
waveOutReset
(
handle
);
...
...
@@ -311,27 +307,14 @@ WinmmOutput::Drain()
}
void
WinmmOutput
::
Cancel
()
WinmmOutput
::
Cancel
()
noexcept
{
Stop
();
}
typedef
AudioOutputWrapper
<
WinmmOutput
>
Wrapper
;
const
struct
AudioOutputPlugin
winmm_output_plugin
=
{
"winmm"
,
winmm_output_test_default_device
,
&
Wrapper
::
Init
,
&
Wrapper
::
Finish
,
nullptr
,
nullptr
,
&
Wrapper
::
Open
,
&
Wrapper
::
Close
,
nullptr
,
nullptr
,
&
Wrapper
::
Play
,
&
Wrapper
::
Drain
,
&
Wrapper
::
Cancel
,
nullptr
,
WinmmOutput
::
Create
,
&
winmm_mixer_plugin
,
};
src/output/plugins/httpd/HttpdInternal.hxx
View file @
31bad5f7
...
...
@@ -26,8 +26,7 @@
#define MPD_OUTPUT_HTTPD_INTERNAL_H
#include "HttpdClient.hxx"
#include "output/Wrapper.hxx"
#include "output/Filtered.hxx"
#include "output/Interface.hxx"
#include "output/Timer.hxx"
#include "thread/Mutex.hxx"
#include "thread/Cond.hxx"
...
...
@@ -49,11 +48,7 @@ class PreparedEncoder;
class
Encoder
;
struct
Tag
;
class
HttpdOutput
final
:
ServerSocket
,
DeferredMonitor
{
friend
struct
AudioOutputWrapper
<
HttpdOutput
>
;
AudioOutput
base
;
class
HttpdOutput
final
:
AudioOutput
,
ServerSocket
,
DeferredMonitor
{
/**
* True if the audio output is open and accepts client
* connections.
...
...
@@ -157,11 +152,9 @@ public:
HttpdOutput
(
EventLoop
&
_loop
,
const
ConfigBlock
&
block
);
~
HttpdOutput
();
static
HttpdOutput
*
Create
(
EventLoop
&
event_loop
,
const
ConfigBlock
&
block
);
static
constexpr
HttpdOutput
*
Cast
(
AudioOutput
*
ao
)
{
return
&
ContainerCast
(
*
ao
,
&
HttpdOutput
::
base
);
static
AudioOutput
*
Create
(
EventLoop
&
event_loop
,
const
ConfigBlock
&
block
)
{
return
new
HttpdOutput
(
event_loop
,
block
);
}
using
DeferredMonitor
::
GetEventLoop
;
...
...
@@ -169,11 +162,11 @@ public:
void
Bind
();
void
Unbind
();
void
Enable
()
{
void
Enable
()
override
{
Bind
();
}
void
Disable
()
{
void
Disable
()
noexcept
override
{
Unbind
();
}
...
...
@@ -187,12 +180,12 @@ public:
/**
* Caller must lock the mutex.
*/
void
Open
(
AudioFormat
&
audio_format
);
void
Open
(
AudioFormat
&
audio_format
)
override
;
/**
* Caller must lock the mutex.
*/
void
Close
();
void
Close
()
noexcept
override
;
/**
* Check whether there is at least one client.
...
...
@@ -227,7 +220,7 @@ public:
void
SendHeader
(
HttpdClient
&
client
)
const
;
gcc_pure
std
::
chrono
::
steady_clock
::
duration
Delay
()
const
noexcept
;
std
::
chrono
::
steady_clock
::
duration
Delay
()
const
noexcept
override
;
/**
* Reads data from the encoder (as much as available) and
...
...
@@ -252,14 +245,14 @@ public:
*/
void
EncodeAndPlay
(
const
void
*
chunk
,
size_t
size
);
void
SendTag
(
const
Tag
&
tag
);
void
SendTag
(
const
Tag
&
tag
)
override
;
size_t
Play
(
const
void
*
chunk
,
size_t
size
);
size_t
Play
(
const
void
*
chunk
,
size_t
size
)
override
;
void
CancelAllClients
();
void
Cancel
();
bool
Pause
();
void
Cancel
()
noexcept
override
;
bool
Pause
()
noexcept
override
;
private
:
virtual
void
RunDeferred
()
override
;
...
...
src/output/plugins/httpd/HttpdOutputPlugin.cxx
View file @
31bad5f7
...
...
@@ -50,8 +50,8 @@ const Domain httpd_output_domain("httpd_output");
inline
HttpdOutput
::
HttpdOutput
(
EventLoop
&
_loop
,
const
ConfigBlock
&
block
)
:
ServerSocket
(
_loop
),
DeferredMonitor
(
_loop
),
base
(
httpd_output_plugin
),
:
AudioOutput
(
FLAG_ENABLE_DISABLE
|
FLAG_PAUSE
),
ServerSocket
(
_loop
),
DeferredMonitor
(
_loop
),
encoder
(
nullptr
),
unflushed_input
(
0
),
metadata
(
nullptr
)
{
...
...
@@ -113,12 +113,6 @@ HttpdOutput::Unbind()
});
}
HttpdOutput
*
HttpdOutput
::
Create
(
EventLoop
&
event_loop
,
const
ConfigBlock
&
block
)
{
return
new
HttpdOutput
(
event_loop
,
block
);
}
/**
* Creates a new #HttpdClient object and adds it into the
* HttpdOutput.clients linked list.
...
...
@@ -246,7 +240,7 @@ HttpdOutput::OpenEncoder(AudioFormat &audio_format)
unflushed_input
=
0
;
}
inline
void
void
HttpdOutput
::
Open
(
AudioFormat
&
audio_format
)
{
assert
(
!
open
);
...
...
@@ -264,8 +258,8 @@ HttpdOutput::Open(AudioFormat &audio_format)
pause
=
false
;
}
inline
void
HttpdOutput
::
Close
()
void
HttpdOutput
::
Close
()
noexcept
{
assert
(
open
);
...
...
@@ -300,7 +294,7 @@ HttpdOutput::SendHeader(HttpdClient &client) const
client
.
PushPage
(
header
);
}
inline
std
::
chrono
::
steady_clock
::
duration
std
::
chrono
::
steady_clock
::
duration
HttpdOutput
::
Delay
()
const
noexcept
{
if
(
!
LockHasClients
()
&&
pause
)
{
...
...
@@ -367,7 +361,7 @@ HttpdOutput::EncodeAndPlay(const void *chunk, size_t size)
BroadcastFromEncoder
();
}
inline
size_t
size_t
HttpdOutput
::
Play
(
const
void
*
chunk
,
size_t
size
)
{
pause
=
false
;
...
...
@@ -383,7 +377,7 @@ HttpdOutput::Play(const void *chunk, size_t size)
}
bool
HttpdOutput
::
Pause
()
HttpdOutput
::
Pause
()
noexcept
{
pause
=
true
;
...
...
@@ -395,7 +389,7 @@ HttpdOutput::Pause()
return
true
;
}
inline
void
void
HttpdOutput
::
SendTag
(
const
Tag
&
tag
)
{
if
(
encoder
->
ImplementsTag
())
{
...
...
@@ -463,29 +457,16 @@ HttpdOutput::CancelAllClients()
}
void
HttpdOutput
::
Cancel
()
HttpdOutput
::
Cancel
()
noexcept
{
BlockingCall
(
GetEventLoop
(),
[
this
](){
CancelAllClients
();
});
}
typedef
AudioOutputWrapper
<
HttpdOutput
>
Wrapper
;
const
struct
AudioOutputPlugin
httpd_output_plugin
=
{
"httpd"
,
nullptr
,
&
Wrapper
::
Init
,
&
Wrapper
::
Finish
,
&
Wrapper
::
Enable
,
&
Wrapper
::
Disable
,
&
Wrapper
::
Open
,
&
Wrapper
::
Close
,
&
Wrapper
::
Delay
,
&
Wrapper
::
SendTag
,
&
Wrapper
::
Play
,
nullptr
,
&
Wrapper
::
Cancel
,
&
Wrapper
::
Pause
,
&
HttpdOutput
::
Create
,
nullptr
,
};
src/output/plugins/sles/SlesOutputPlugin.cxx
View file @
31bad5f7
...
...
@@ -24,7 +24,6 @@
#include "Play.hxx"
#include "AndroidSimpleBufferQueue.hxx"
#include "../../OutputAPI.hxx"
#include "../../Wrapper.hxx"
#include "thread/Mutex.hxx"
#include "thread/Cond.hxx"
#include "util/Macros.hxx"
...
...
@@ -37,14 +36,10 @@
#include <stdexcept>
class
SlesOutput
{
friend
struct
AudioOutputWrapper
<
SlesOutput
>
;
class
SlesOutput
final
:
AudioOutput
{
static
constexpr
unsigned
N_BUFFERS
=
3
;
static
constexpr
size_t
BUFFER_SIZE
=
65536
;
AudioOutput
base
;
SLES
::
Object
engine_object
,
mix_object
,
play_object
;
SLES
::
Play
play
;
SLES
::
AndroidSimpleBufferQueue
queue
;
...
...
@@ -86,30 +81,28 @@ class SlesOutput {
*/
uint8_t
buffers
[
N_BUFFERS
][
BUFFER_SIZE
];
public
:
SlesOutput
();
SlesOutput
()
:
AudioOutput
(
FLAG_PAUSE
)
{}
operator
AudioOutput
*
()
{
return
&
base
;
public
:
static
AudioOutput
*
Create
(
EventLoop
&
,
const
ConfigBlock
&
)
{
return
new
SlesOutput
();
}
static
SlesOutput
*
Create
(
EventLoop
&
event_loop
,
const
ConfigBlock
&
block
);
void
Open
(
AudioFormat
&
audio_format
);
void
Close
();
private
:
void
Open
(
AudioFormat
&
audio_format
)
override
;
void
Close
()
noexcept
override
;
std
::
chrono
::
steady_clock
::
duration
Delay
()
noexcept
{
std
::
chrono
::
steady_clock
::
duration
Delay
()
const
noexcept
override
{
return
pause
&&
!
cancel
?
std
::
chrono
::
milliseconds
(
100
)
:
std
::
chrono
::
steady_clock
::
duration
::
zero
();
}
size_t
Play
(
const
void
*
chunk
,
size_t
size
);
size_t
Play
(
const
void
*
chunk
,
size_t
size
)
override
;
void
Drain
();
void
Cancel
();
bool
Pause
();
void
Drain
()
override
;
void
Cancel
()
noexcept
override
;
bool
Pause
()
noexcept
override
;
private
:
void
PlayedCallback
();
...
...
@@ -129,12 +122,7 @@ private:
static
constexpr
Domain
sles_domain
(
"sles"
);
SlesOutput
::
SlesOutput
()
:
base
(
sles_output_plugin
)
{
}
inline
void
void
SlesOutput
::
Open
(
AudioFormat
&
audio_format
)
{
SLresult
result
;
...
...
@@ -300,8 +288,8 @@ SlesOutput::Open(AudioFormat &audio_format)
audio_format
.
format
=
SampleFormat
::
S16
;
}
inline
void
SlesOutput
::
Close
()
void
SlesOutput
::
Close
()
noexcept
{
play
.
SetPlayState
(
SL_PLAYSTATE_STOPPED
);
play_object
.
Destroy
();
...
...
@@ -309,7 +297,7 @@ SlesOutput::Close()
engine_object
.
Destroy
();
}
inline
size_t
size_t
SlesOutput
::
Play
(
const
void
*
chunk
,
size_t
size
)
{
cancel
=
false
;
...
...
@@ -348,7 +336,7 @@ SlesOutput::Play(const void *chunk, size_t size)
return
nbytes
;
}
inline
void
void
SlesOutput
::
Drain
()
{
const
std
::
lock_guard
<
Mutex
>
protect
(
mutex
);
...
...
@@ -359,8 +347,8 @@ SlesOutput::Drain()
cond
.
wait
(
mutex
);
}
inline
void
SlesOutput
::
Cancel
()
void
SlesOutput
::
Cancel
()
noexcept
{
pause
=
true
;
cancel
=
true
;
...
...
@@ -379,8 +367,8 @@ SlesOutput::Cancel()
filled
=
0
;
}
inline
bool
SlesOutput
::
Pause
()
bool
SlesOutput
::
Pause
()
noexcept
{
cancel
=
false
;
...
...
@@ -415,28 +403,9 @@ sles_test_default_device()
return
true
;
}
inline
SlesOutput
*
SlesOutput
::
Create
(
EventLoop
&
,
const
ConfigBlock
&
)
{
return
new
SlesOutput
();
}
typedef
AudioOutputWrapper
<
SlesOutput
>
Wrapper
;
const
struct
AudioOutputPlugin
sles_output_plugin
=
{
"sles"
,
sles_test_default_device
,
&
Wrapper
::
Init
,
&
Wrapper
::
Finish
,
nullptr
,
nullptr
,
&
Wrapper
::
Open
,
&
Wrapper
::
Close
,
&
Wrapper
::
Delay
,
nullptr
,
&
Wrapper
::
Play
,
&
Wrapper
::
Drain
,
&
Wrapper
::
Cancel
,
&
Wrapper
::
Pause
,
SlesOutput
::
Create
,
nullptr
,
};
test/run_output.cxx
View file @
31bad5f7
...
...
@@ -34,13 +34,15 @@
#include "util/ScopeExit.hxx"
#include "Log.hxx"
#include <memory>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
static
AudioOutput
*
static
std
::
unique_ptr
<
AudioOutput
>
load_audio_output
(
EventLoop
&
event_loop
,
const
char
*
name
)
{
const
auto
*
block
=
config_find_block
(
ConfigBlockOption
::
AUDIO_OUTPUT
,
...
...
@@ -58,7 +60,8 @@ load_audio_output(EventLoop &event_loop, const char *name)
throw
FormatRuntimeError
(
"No such audio output plugin: %s"
,
plugin_name
);
return
ao_plugin_init
(
event_loop
,
*
plugin
,
*
block
);
return
std
::
unique_ptr
<
AudioOutput
>
(
ao_plugin_init
(
event_loop
,
*
plugin
,
*
block
));
}
static
void
...
...
@@ -66,11 +69,11 @@ run_output(AudioOutput &ao, AudioFormat audio_format)
{
/* open the audio output */
ao
_plugin_enable
(
ao
);
AtScopeExit
(
&
ao
)
{
ao
_plugin_disable
(
ao
);
};
ao
.
Enable
(
);
AtScopeExit
(
&
ao
)
{
ao
.
Disable
(
);
};
ao
_plugin_open
(
ao
,
audio_format
);
AtScopeExit
(
&
ao
)
{
ao
_plugin_close
(
ao
);
};
ao
.
Open
(
audio_format
);
AtScopeExit
(
&
ao
)
{
ao
.
Close
(
);
};
fprintf
(
stderr
,
"audio_format=%s
\n
"
,
ToString
(
audio_format
).
c_str
());
...
...
@@ -93,8 +96,7 @@ run_output(AudioOutput &ao, AudioFormat audio_format)
size_t
play_length
=
(
length
/
frame_size
)
*
frame_size
;
if
(
play_length
>
0
)
{
size_t
consumed
=
ao_plugin_play
(
ao
,
buffer
,
play_length
);
size_t
consumed
=
ao
.
Play
(
buffer
,
play_length
);
assert
(
consumed
<=
length
);
assert
(
consumed
%
frame_size
==
0
);
...
...
@@ -126,7 +128,7 @@ try {
/* initialize the audio output */
auto
*
ao
=
load_audio_output
(
io_thread
.
GetEventLoop
(),
argv
[
2
]);
auto
ao
=
load_audio_output
(
io_thread
.
GetEventLoop
(),
argv
[
2
]);
/* parse the audio format */
...
...
@@ -139,7 +141,7 @@ try {
/* cleanup and exit */
ao
_plugin_finish
(
ao
);
ao
.
reset
(
);
config_global_finish
();
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment