output: move functions into the AudioOutput struct
This commit is contained in:
parent
cb7366f472
commit
4657a3bd0f
@ -963,9 +963,9 @@ OUTPUT_API_SRC = \
|
|||||||
src/output/Internal.hxx \
|
src/output/Internal.hxx \
|
||||||
src/output/Registry.cxx src/output/Registry.hxx \
|
src/output/Registry.cxx src/output/Registry.hxx \
|
||||||
src/output/MultipleOutputs.cxx src/output/MultipleOutputs.hxx \
|
src/output/MultipleOutputs.cxx src/output/MultipleOutputs.hxx \
|
||||||
src/output/OutputThread.cxx src/output/OutputThread.hxx \
|
src/output/OutputThread.cxx \
|
||||||
src/output/Domain.cxx src/output/Domain.hxx \
|
src/output/Domain.cxx src/output/Domain.hxx \
|
||||||
src/output/OutputControl.cxx src/output/OutputControl.hxx \
|
src/output/OutputControl.cxx \
|
||||||
src/output/OutputState.cxx src/output/OutputState.hxx \
|
src/output/OutputState.cxx src/output/OutputState.hxx \
|
||||||
src/output/OutputPrint.cxx src/output/OutputPrint.hxx \
|
src/output/OutputPrint.cxx src/output/OutputPrint.hxx \
|
||||||
src/output/OutputCommand.cxx src/output/OutputCommand.hxx \
|
src/output/OutputCommand.cxx src/output/OutputCommand.hxx \
|
||||||
|
@ -147,14 +147,11 @@ audio_output_load_mixer(AudioOutput *ao,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ao_base_init(AudioOutput *ao,
|
AudioOutput::Configure(const config_param ¶m, Error &error)
|
||||||
const config_param ¶m, Error &error)
|
|
||||||
{
|
{
|
||||||
assert(ao != nullptr);
|
|
||||||
|
|
||||||
if (!param.IsNull()) {
|
if (!param.IsNull()) {
|
||||||
ao->name = param.GetBlockValue(AUDIO_OUTPUT_NAME);
|
name = param.GetBlockValue(AUDIO_OUTPUT_NAME);
|
||||||
if (ao->name == nullptr) {
|
if (name == nullptr) {
|
||||||
error.Set(config_domain,
|
error.Set(config_domain,
|
||||||
"Missing \"name\" configuration");
|
"Missing \"name\" configuration");
|
||||||
return false;
|
return false;
|
||||||
@ -163,26 +160,26 @@ ao_base_init(AudioOutput *ao,
|
|||||||
const char *p = param.GetBlockValue(AUDIO_OUTPUT_FORMAT);
|
const char *p = param.GetBlockValue(AUDIO_OUTPUT_FORMAT);
|
||||||
if (p != nullptr) {
|
if (p != nullptr) {
|
||||||
bool success =
|
bool success =
|
||||||
audio_format_parse(ao->config_audio_format,
|
audio_format_parse(config_audio_format,
|
||||||
p, true, error);
|
p, true, error);
|
||||||
if (!success)
|
if (!success)
|
||||||
return false;
|
return false;
|
||||||
} else
|
} else
|
||||||
ao->config_audio_format.Clear();
|
config_audio_format.Clear();
|
||||||
} else {
|
} else {
|
||||||
ao->name = "default detected output";
|
name = "default detected output";
|
||||||
|
|
||||||
ao->config_audio_format.Clear();
|
config_audio_format.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
ao->tags = param.GetBlockValue("tags", true);
|
tags = param.GetBlockValue("tags", true);
|
||||||
ao->always_on = param.GetBlockValue("always_on", false);
|
always_on = param.GetBlockValue("always_on", false);
|
||||||
ao->enabled = param.GetBlockValue("enabled", true);
|
enabled = param.GetBlockValue("enabled", true);
|
||||||
|
|
||||||
/* set up the filter chain */
|
/* set up the filter chain */
|
||||||
|
|
||||||
ao->filter = filter_chain_new();
|
filter = filter_chain_new();
|
||||||
assert(ao->filter != nullptr);
|
assert(filter != nullptr);
|
||||||
|
|
||||||
/* create the normalization filter (if configured) */
|
/* create the normalization filter (if configured) */
|
||||||
|
|
||||||
@ -192,12 +189,12 @@ ao_base_init(AudioOutput *ao,
|
|||||||
IgnoreError());
|
IgnoreError());
|
||||||
assert(normalize_filter != nullptr);
|
assert(normalize_filter != nullptr);
|
||||||
|
|
||||||
filter_chain_append(*ao->filter, "normalize",
|
filter_chain_append(*filter, "normalize",
|
||||||
autoconvert_filter_new(normalize_filter));
|
autoconvert_filter_new(normalize_filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
Error filter_error;
|
Error filter_error;
|
||||||
filter_chain_parse(*ao->filter,
|
filter_chain_parse(*filter,
|
||||||
param.GetBlockValue(AUDIO_FILTERS, ""),
|
param.GetBlockValue(AUDIO_FILTERS, ""),
|
||||||
filter_error);
|
filter_error);
|
||||||
|
|
||||||
@ -206,7 +203,7 @@ ao_base_init(AudioOutput *ao,
|
|||||||
if (filter_error.IsDefined())
|
if (filter_error.IsDefined())
|
||||||
FormatError(filter_error,
|
FormatError(filter_error,
|
||||||
"Failed to initialize filter chain for '%s'",
|
"Failed to initialize filter chain for '%s'",
|
||||||
ao->name);
|
name);
|
||||||
|
|
||||||
/* done */
|
/* done */
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "AudioFormat.hxx"
|
#include "AudioFormat.hxx"
|
||||||
#include "pcm/PcmBuffer.hxx"
|
#include "pcm/PcmBuffer.hxx"
|
||||||
#include "pcm/PcmDither.hxx"
|
#include "pcm/PcmDither.hxx"
|
||||||
|
#include "ReplayGainInfo.hxx"
|
||||||
#include "thread/Mutex.hxx"
|
#include "thread/Mutex.hxx"
|
||||||
#include "thread/Cond.hxx"
|
#include "thread/Cond.hxx"
|
||||||
#include "thread/Thread.hxx"
|
#include "thread/Thread.hxx"
|
||||||
@ -266,6 +267,106 @@ struct AudioOutput {
|
|||||||
|
|
||||||
AudioOutput(const AudioOutputPlugin &_plugin);
|
AudioOutput(const AudioOutputPlugin &_plugin);
|
||||||
~AudioOutput();
|
~AudioOutput();
|
||||||
|
|
||||||
|
bool Configure(const config_param ¶m, Error &error);
|
||||||
|
|
||||||
|
void StartThread();
|
||||||
|
void StopThread();
|
||||||
|
|
||||||
|
void Finish();
|
||||||
|
|
||||||
|
bool IsOpen() const {
|
||||||
|
return open;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsCommandFinished() const {
|
||||||
|
return command == AO_COMMAND_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for command completion.
|
||||||
|
*
|
||||||
|
* Caller must lock the mutex.
|
||||||
|
*/
|
||||||
|
void WaitForCommand();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a command, but does not wait for completion.
|
||||||
|
*
|
||||||
|
* Caller must lock the mutex.
|
||||||
|
*/
|
||||||
|
void CommandAsync(audio_output_command cmd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a command to the #AudioOutput object and waits for
|
||||||
|
* completion.
|
||||||
|
*
|
||||||
|
* Caller must lock the mutex.
|
||||||
|
*/
|
||||||
|
void CommandWait(audio_output_command cmd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lock the #AudioOutput object and execute the command
|
||||||
|
* synchronously.
|
||||||
|
*/
|
||||||
|
void LockCommandWait(audio_output_command cmd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables the device.
|
||||||
|
*/
|
||||||
|
void LockEnableWait();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables the device.
|
||||||
|
*/
|
||||||
|
void LockDisableWait();
|
||||||
|
|
||||||
|
void LockPauseAsync();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same LockCloseWait(), but expects the lock to be
|
||||||
|
* held by the caller.
|
||||||
|
*/
|
||||||
|
void CloseWait();
|
||||||
|
void LockCloseWait();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the audio output, but if the "always_on" flag is set, put it
|
||||||
|
* into pause mode instead.
|
||||||
|
*/
|
||||||
|
void LockRelease();
|
||||||
|
|
||||||
|
void SetReplayGainMode(ReplayGainMode mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Caller must lock the mutex.
|
||||||
|
*/
|
||||||
|
bool Open(const AudioFormat audio_format, const MusicPipe &mp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens or closes the device, depending on the "enabled"
|
||||||
|
* flag.
|
||||||
|
*
|
||||||
|
* @return true if the device is open
|
||||||
|
*/
|
||||||
|
bool LockUpdate(const AudioFormat audio_format,
|
||||||
|
const MusicPipe &mp);
|
||||||
|
|
||||||
|
void LockPlay();
|
||||||
|
|
||||||
|
void LockDrainAsync();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the "allow_play" flag and send the "CANCEL" command
|
||||||
|
* asynchronously. To finish the operation, the caller has to
|
||||||
|
* call LockAllowPlay().
|
||||||
|
*/
|
||||||
|
void LockCancelAsync();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the "allow_play" and signal the thread.
|
||||||
|
*/
|
||||||
|
void LockAllowPlay();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -274,27 +375,11 @@ struct AudioOutput {
|
|||||||
*/
|
*/
|
||||||
extern struct notify audio_output_client_notify;
|
extern struct notify audio_output_client_notify;
|
||||||
|
|
||||||
static inline bool
|
|
||||||
audio_output_is_open(const AudioOutput *ao)
|
|
||||||
{
|
|
||||||
return ao->open;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool
|
|
||||||
audio_output_command_is_finished(const AudioOutput *ao)
|
|
||||||
{
|
|
||||||
return ao->command == AO_COMMAND_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioOutput *
|
AudioOutput *
|
||||||
audio_output_new(const config_param ¶m,
|
audio_output_new(const config_param ¶m,
|
||||||
PlayerControl &pc,
|
PlayerControl &pc,
|
||||||
Error &error);
|
Error &error);
|
||||||
|
|
||||||
bool
|
|
||||||
ao_base_init(AudioOutput *ao,
|
|
||||||
const config_param ¶m, Error &error);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
audio_output_free(AudioOutput *ao);
|
audio_output_free(AudioOutput *ao);
|
||||||
|
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
#include "MultipleOutputs.hxx"
|
#include "MultipleOutputs.hxx"
|
||||||
#include "PlayerControl.hxx"
|
#include "PlayerControl.hxx"
|
||||||
#include "Internal.hxx"
|
#include "Internal.hxx"
|
||||||
#include "OutputControl.hxx"
|
|
||||||
#include "Domain.hxx"
|
#include "Domain.hxx"
|
||||||
#include "MusicBuffer.hxx"
|
#include "MusicBuffer.hxx"
|
||||||
#include "MusicPipe.hxx"
|
#include "MusicPipe.hxx"
|
||||||
@ -45,8 +44,8 @@ MultipleOutputs::MultipleOutputs()
|
|||||||
MultipleOutputs::~MultipleOutputs()
|
MultipleOutputs::~MultipleOutputs()
|
||||||
{
|
{
|
||||||
for (auto i : outputs) {
|
for (auto i : outputs) {
|
||||||
audio_output_disable(i);
|
i->LockDisableWait();
|
||||||
audio_output_finish(i);
|
i->Finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,9 +110,9 @@ MultipleOutputs::EnableDisable()
|
|||||||
|
|
||||||
if (ao->enabled != enabled) {
|
if (ao->enabled != enabled) {
|
||||||
if (ao->enabled)
|
if (ao->enabled)
|
||||||
audio_output_enable(ao);
|
ao->LockEnableWait();
|
||||||
else
|
else
|
||||||
audio_output_disable(ao);
|
ao->LockDisableWait();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,8 +122,7 @@ MultipleOutputs::AllFinished() const
|
|||||||
{
|
{
|
||||||
for (auto ao : outputs) {
|
for (auto ao : outputs) {
|
||||||
const ScopeLock protect(ao->mutex);
|
const ScopeLock protect(ao->mutex);
|
||||||
if (audio_output_is_open(ao) &&
|
if (ao->IsOpen() && !ao->IsCommandFinished())
|
||||||
!audio_output_command_is_finished(ao))
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,7 +140,7 @@ void
|
|||||||
MultipleOutputs::AllowPlay()
|
MultipleOutputs::AllowPlay()
|
||||||
{
|
{
|
||||||
for (auto ao : outputs)
|
for (auto ao : outputs)
|
||||||
audio_output_allow_play(ao);
|
ao->LockAllowPlay();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -169,7 +167,7 @@ MultipleOutputs::Update()
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (auto ao : outputs)
|
for (auto ao : outputs)
|
||||||
ret = audio_output_update(ao, input_audio_format, *pipe)
|
ret = ao->LockUpdate(input_audio_format, *pipe)
|
||||||
|| ret;
|
|| ret;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -179,7 +177,7 @@ void
|
|||||||
MultipleOutputs::SetReplayGainMode(ReplayGainMode mode)
|
MultipleOutputs::SetReplayGainMode(ReplayGainMode mode)
|
||||||
{
|
{
|
||||||
for (auto ao : outputs)
|
for (auto ao : outputs)
|
||||||
audio_output_set_replay_gain_mode(ao, mode);
|
ao->SetReplayGainMode(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -199,7 +197,7 @@ MultipleOutputs::Play(music_chunk *chunk, Error &error)
|
|||||||
pipe->Push(chunk);
|
pipe->Push(chunk);
|
||||||
|
|
||||||
for (auto ao : outputs)
|
for (auto ao : outputs)
|
||||||
audio_output_play(ao);
|
ao->LockPlay();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -387,7 +385,7 @@ MultipleOutputs::Pause()
|
|||||||
Update();
|
Update();
|
||||||
|
|
||||||
for (auto ao : outputs)
|
for (auto ao : outputs)
|
||||||
audio_output_pause(ao);
|
ao->LockPauseAsync();
|
||||||
|
|
||||||
WaitAll();
|
WaitAll();
|
||||||
}
|
}
|
||||||
@ -396,7 +394,7 @@ void
|
|||||||
MultipleOutputs::Drain()
|
MultipleOutputs::Drain()
|
||||||
{
|
{
|
||||||
for (auto ao : outputs)
|
for (auto ao : outputs)
|
||||||
audio_output_drain_async(ao);
|
ao->LockDrainAsync();
|
||||||
|
|
||||||
WaitAll();
|
WaitAll();
|
||||||
}
|
}
|
||||||
@ -407,7 +405,7 @@ MultipleOutputs::Cancel()
|
|||||||
/* send the cancel() command to all audio outputs */
|
/* send the cancel() command to all audio outputs */
|
||||||
|
|
||||||
for (auto ao : outputs)
|
for (auto ao : outputs)
|
||||||
audio_output_cancel(ao);
|
ao->LockCancelAsync();
|
||||||
|
|
||||||
WaitAll();
|
WaitAll();
|
||||||
|
|
||||||
@ -430,7 +428,7 @@ void
|
|||||||
MultipleOutputs::Close()
|
MultipleOutputs::Close()
|
||||||
{
|
{
|
||||||
for (auto ao : outputs)
|
for (auto ao : outputs)
|
||||||
audio_output_close(ao);
|
ao->LockCloseWait();
|
||||||
|
|
||||||
if (pipe != nullptr) {
|
if (pipe != nullptr) {
|
||||||
assert(buffer != nullptr);
|
assert(buffer != nullptr);
|
||||||
@ -451,7 +449,7 @@ void
|
|||||||
MultipleOutputs::Release()
|
MultipleOutputs::Release()
|
||||||
{
|
{
|
||||||
for (auto ao : outputs)
|
for (auto ao : outputs)
|
||||||
audio_output_release(ao);
|
ao->LockRelease();
|
||||||
|
|
||||||
if (pipe != nullptr) {
|
if (pipe != nullptr) {
|
||||||
assert(buffer != nullptr);
|
assert(buffer != nullptr);
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||||
* http://www.musicpd.org
|
* http://www.musicpd.org
|
||||||
@ -19,8 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "OutputControl.hxx"
|
|
||||||
#include "OutputThread.hxx"
|
|
||||||
#include "Internal.hxx"
|
#include "Internal.hxx"
|
||||||
#include "OutputPlugin.hxx"
|
#include "OutputPlugin.hxx"
|
||||||
#include "Domain.hxx"
|
#include "Domain.hxx"
|
||||||
@ -38,126 +35,97 @@ static constexpr unsigned REOPEN_AFTER = 10;
|
|||||||
|
|
||||||
struct notify audio_output_client_notify;
|
struct notify audio_output_client_notify;
|
||||||
|
|
||||||
/**
|
void
|
||||||
* Waits for command completion.
|
AudioOutput::WaitForCommand()
|
||||||
*
|
|
||||||
* @param ao the #AudioOutput instance; must be locked
|
|
||||||
*/
|
|
||||||
static void ao_command_wait(AudioOutput *ao)
|
|
||||||
{
|
{
|
||||||
while (ao->command != AO_COMMAND_NONE) {
|
while (!IsCommandFinished()) {
|
||||||
ao->mutex.unlock();
|
mutex.unlock();
|
||||||
audio_output_client_notify.Wait();
|
audio_output_client_notify.Wait();
|
||||||
ao->mutex.lock();
|
mutex.lock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void
|
||||||
* Sends a command to the #AudioOutput object, but does not wait for
|
AudioOutput::CommandAsync(audio_output_command cmd)
|
||||||
* completion.
|
|
||||||
*
|
|
||||||
* @param ao the #AudioOutput instance; must be locked
|
|
||||||
*/
|
|
||||||
static void ao_command_async(AudioOutput *ao,
|
|
||||||
enum audio_output_command cmd)
|
|
||||||
{
|
{
|
||||||
assert(ao->command == AO_COMMAND_NONE);
|
assert(IsCommandFinished());
|
||||||
ao->command = cmd;
|
|
||||||
ao->cond.signal();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
command = cmd;
|
||||||
* Sends a command to the #AudioOutput object and waits for
|
cond.signal();
|
||||||
* completion.
|
|
||||||
*
|
|
||||||
* @param ao the #AudioOutput instance; must be locked
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
ao_command(AudioOutput *ao, enum audio_output_command cmd)
|
|
||||||
{
|
|
||||||
ao_command_async(ao, cmd);
|
|
||||||
ao_command_wait(ao);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lock the #AudioOutput object and execute the command
|
|
||||||
* synchronously.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
ao_lock_command(AudioOutput *ao, enum audio_output_command cmd)
|
|
||||||
{
|
|
||||||
const ScopeLock protect(ao->mutex);
|
|
||||||
ao_command(ao, cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
audio_output_set_replay_gain_mode(AudioOutput *ao,
|
AudioOutput::CommandWait(audio_output_command cmd)
|
||||||
ReplayGainMode mode)
|
|
||||||
{
|
{
|
||||||
if (ao->replay_gain_filter != nullptr)
|
CommandAsync(cmd);
|
||||||
replay_gain_filter_set_mode(ao->replay_gain_filter, mode);
|
WaitForCommand();
|
||||||
if (ao->other_replay_gain_filter != nullptr)
|
|
||||||
replay_gain_filter_set_mode(ao->other_replay_gain_filter, mode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
audio_output_enable(AudioOutput *ao)
|
AudioOutput::LockCommandWait(audio_output_command cmd)
|
||||||
{
|
{
|
||||||
if (!ao->thread.IsDefined()) {
|
const ScopeLock protect(mutex);
|
||||||
if (ao->plugin.enable == nullptr) {
|
CommandWait(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AudioOutput::SetReplayGainMode(ReplayGainMode mode)
|
||||||
|
{
|
||||||
|
if (replay_gain_filter != nullptr)
|
||||||
|
replay_gain_filter_set_mode(replay_gain_filter, mode);
|
||||||
|
if (other_replay_gain_filter != nullptr)
|
||||||
|
replay_gain_filter_set_mode(other_replay_gain_filter, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AudioOutput::LockEnableWait()
|
||||||
|
{
|
||||||
|
if (!thread.IsDefined()) {
|
||||||
|
if (plugin.enable == nullptr) {
|
||||||
/* don't bother to start the thread now if the
|
/* don't bother to start the thread now if the
|
||||||
device doesn't even have a enable() method;
|
device doesn't even have a enable() method;
|
||||||
just assign the variable and we're done */
|
just assign the variable and we're done */
|
||||||
ao->really_enabled = true;
|
really_enabled = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
audio_output_thread_start(ao);
|
StartThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
ao_lock_command(ao, AO_COMMAND_ENABLE);
|
LockCommandWait(AO_COMMAND_ENABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
audio_output_disable(AudioOutput *ao)
|
AudioOutput::LockDisableWait()
|
||||||
{
|
{
|
||||||
if (!ao->thread.IsDefined()) {
|
if (!thread.IsDefined()) {
|
||||||
if (ao->plugin.disable == nullptr)
|
if (plugin.disable == nullptr)
|
||||||
ao->really_enabled = false;
|
really_enabled = false;
|
||||||
else
|
else
|
||||||
/* if there's no thread yet, the device cannot
|
/* if there's no thread yet, the device cannot
|
||||||
be enabled */
|
be enabled */
|
||||||
assert(!ao->really_enabled);
|
assert(!really_enabled);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ao_lock_command(ao, AO_COMMAND_DISABLE);
|
LockCommandWait(AO_COMMAND_DISABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
inline bool
|
||||||
* Object must be locked (and unlocked) by the caller.
|
AudioOutput::Open(const AudioFormat audio_format, const MusicPipe &mp)
|
||||||
*/
|
|
||||||
static bool
|
|
||||||
audio_output_open(AudioOutput *ao,
|
|
||||||
const AudioFormat audio_format,
|
|
||||||
const MusicPipe &mp)
|
|
||||||
{
|
{
|
||||||
bool open;
|
assert(allow_play);
|
||||||
|
|
||||||
assert(ao != nullptr);
|
|
||||||
assert(ao->allow_play);
|
|
||||||
assert(audio_format.IsValid());
|
assert(audio_format.IsValid());
|
||||||
|
|
||||||
ao->fail_timer.Reset();
|
fail_timer.Reset();
|
||||||
|
|
||||||
if (ao->open && audio_format == ao->in_audio_format) {
|
if (open && audio_format == in_audio_format) {
|
||||||
assert(ao->pipe == &mp ||
|
assert(pipe == &mp || (always_on && pause));
|
||||||
(ao->always_on && ao->pause));
|
|
||||||
|
|
||||||
if (ao->pause) {
|
if (pause) {
|
||||||
ao->chunk = nullptr;
|
chunk = nullptr;
|
||||||
ao->pipe = ∓
|
pipe = ∓
|
||||||
|
|
||||||
/* unpause with the CANCEL command; this is a
|
/* unpause with the CANCEL command; this is a
|
||||||
hack, but suits well for forcing the thread
|
hack, but suits well for forcing the thread
|
||||||
@ -166,160 +134,162 @@ audio_output_open(AudioOutput *ao,
|
|||||||
|
|
||||||
/* we're not using audio_output_cancel() here,
|
/* we're not using audio_output_cancel() here,
|
||||||
because that function is asynchronous */
|
because that function is asynchronous */
|
||||||
ao_command(ao, AO_COMMAND_CANCEL);
|
CommandWait(AO_COMMAND_CANCEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ao->in_audio_format = audio_format;
|
in_audio_format = audio_format;
|
||||||
ao->chunk = nullptr;
|
chunk = nullptr;
|
||||||
|
|
||||||
ao->pipe = ∓
|
pipe = ∓
|
||||||
|
|
||||||
if (!ao->thread.IsDefined())
|
if (!thread.IsDefined())
|
||||||
audio_output_thread_start(ao);
|
StartThread();
|
||||||
|
|
||||||
ao_command(ao, ao->open ? AO_COMMAND_REOPEN : AO_COMMAND_OPEN);
|
CommandWait(open ? AO_COMMAND_REOPEN : AO_COMMAND_OPEN);
|
||||||
open = ao->open;
|
const bool open2 = open;
|
||||||
|
|
||||||
if (open && ao->mixer != nullptr) {
|
if (open2 && mixer != nullptr) {
|
||||||
Error error;
|
Error error;
|
||||||
if (!mixer_open(ao->mixer, error))
|
if (!mixer_open(mixer, error))
|
||||||
FormatWarning(output_domain,
|
FormatWarning(output_domain,
|
||||||
"Failed to open mixer for '%s'",
|
"Failed to open mixer for '%s'", name);
|
||||||
ao->name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return open;
|
return open2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void
|
||||||
* Same as audio_output_close(), but expects the lock to be held by
|
AudioOutput::CloseWait()
|
||||||
* the caller.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
audio_output_close_locked(AudioOutput *ao)
|
|
||||||
{
|
{
|
||||||
assert(ao != nullptr);
|
assert(allow_play);
|
||||||
assert(ao->allow_play);
|
|
||||||
|
|
||||||
if (ao->mixer != nullptr)
|
if (mixer != nullptr)
|
||||||
mixer_auto_close(ao->mixer);
|
mixer_auto_close(mixer);
|
||||||
|
|
||||||
assert(!ao->open || !ao->fail_timer.IsDefined());
|
assert(!open || !fail_timer.IsDefined());
|
||||||
|
|
||||||
if (ao->open)
|
if (open)
|
||||||
ao_command(ao, AO_COMMAND_CLOSE);
|
CommandWait(AO_COMMAND_CLOSE);
|
||||||
else
|
else
|
||||||
ao->fail_timer.Reset();
|
fail_timer.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
audio_output_update(AudioOutput *ao,
|
AudioOutput::LockUpdate(const AudioFormat audio_format,
|
||||||
const AudioFormat audio_format,
|
|
||||||
const MusicPipe &mp)
|
const MusicPipe &mp)
|
||||||
{
|
{
|
||||||
const ScopeLock protect(ao->mutex);
|
const ScopeLock protect(mutex);
|
||||||
|
|
||||||
if (ao->enabled && ao->really_enabled) {
|
if (enabled && really_enabled) {
|
||||||
if (ao->fail_timer.Check(REOPEN_AFTER * 1000)) {
|
if (fail_timer.Check(REOPEN_AFTER * 1000)) {
|
||||||
return audio_output_open(ao, audio_format, mp);
|
return Open(audio_format, mp);
|
||||||
}
|
}
|
||||||
} else if (audio_output_is_open(ao))
|
} else if (IsOpen())
|
||||||
audio_output_close_locked(ao);
|
CloseWait();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
audio_output_play(AudioOutput *ao)
|
AudioOutput::LockPlay()
|
||||||
{
|
{
|
||||||
const ScopeLock protect(ao->mutex);
|
const ScopeLock protect(mutex);
|
||||||
|
|
||||||
assert(ao->allow_play);
|
assert(allow_play);
|
||||||
|
|
||||||
if (audio_output_is_open(ao) && !ao->in_playback_loop &&
|
if (IsOpen() && !in_playback_loop && !woken_for_play) {
|
||||||
!ao->woken_for_play) {
|
woken_for_play = true;
|
||||||
ao->woken_for_play = true;
|
cond.signal();
|
||||||
ao->cond.signal();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_output_pause(AudioOutput *ao)
|
void
|
||||||
|
AudioOutput::LockPauseAsync()
|
||||||
{
|
{
|
||||||
if (ao->mixer != nullptr && ao->plugin.pause == nullptr)
|
if (mixer != nullptr && plugin.pause == nullptr)
|
||||||
/* the device has no pause mode: close the mixer,
|
/* the device has no pause mode: close the mixer,
|
||||||
unless its "global" flag is set (checked by
|
unless its "global" flag is set (checked by
|
||||||
mixer_auto_close()) */
|
mixer_auto_close()) */
|
||||||
mixer_auto_close(ao->mixer);
|
mixer_auto_close(mixer);
|
||||||
|
|
||||||
const ScopeLock protect(ao->mutex);
|
const ScopeLock protect(mutex);
|
||||||
|
|
||||||
assert(ao->allow_play);
|
assert(allow_play);
|
||||||
if (audio_output_is_open(ao))
|
if (IsOpen())
|
||||||
ao_command_async(ao, AO_COMMAND_PAUSE);
|
CommandAsync(AO_COMMAND_PAUSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
audio_output_drain_async(AudioOutput *ao)
|
AudioOutput::LockDrainAsync()
|
||||||
{
|
{
|
||||||
const ScopeLock protect(ao->mutex);
|
const ScopeLock protect(mutex);
|
||||||
|
|
||||||
assert(ao->allow_play);
|
assert(allow_play);
|
||||||
if (audio_output_is_open(ao))
|
if (IsOpen())
|
||||||
ao_command_async(ao, AO_COMMAND_DRAIN);
|
CommandAsync(AO_COMMAND_DRAIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_output_cancel(AudioOutput *ao)
|
void
|
||||||
|
AudioOutput::LockCancelAsync()
|
||||||
{
|
{
|
||||||
const ScopeLock protect(ao->mutex);
|
const ScopeLock protect(mutex);
|
||||||
|
|
||||||
if (audio_output_is_open(ao)) {
|
if (IsOpen()) {
|
||||||
ao->allow_play = false;
|
allow_play = false;
|
||||||
ao_command_async(ao, AO_COMMAND_CANCEL);
|
CommandAsync(AO_COMMAND_CANCEL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
audio_output_allow_play(AudioOutput *ao)
|
AudioOutput::LockAllowPlay()
|
||||||
{
|
{
|
||||||
const ScopeLock protect(ao->mutex);
|
const ScopeLock protect(mutex);
|
||||||
|
|
||||||
ao->allow_play = true;
|
allow_play = true;
|
||||||
if (audio_output_is_open(ao))
|
if (IsOpen())
|
||||||
ao->cond.signal();
|
cond.signal();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
audio_output_release(AudioOutput *ao)
|
AudioOutput::LockRelease()
|
||||||
{
|
{
|
||||||
if (ao->always_on)
|
if (always_on)
|
||||||
audio_output_pause(ao);
|
LockPauseAsync();
|
||||||
else
|
else
|
||||||
audio_output_close(ao);
|
LockCloseWait();
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_output_close(AudioOutput *ao)
|
void
|
||||||
|
AudioOutput::LockCloseWait()
|
||||||
{
|
{
|
||||||
assert(ao != nullptr);
|
assert(!open || !fail_timer.IsDefined());
|
||||||
assert(!ao->open || !ao->fail_timer.IsDefined());
|
|
||||||
|
|
||||||
const ScopeLock protect(ao->mutex);
|
const ScopeLock protect(mutex);
|
||||||
audio_output_close_locked(ao);
|
CloseWait();
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_output_finish(AudioOutput *ao)
|
void
|
||||||
|
AudioOutput::StopThread()
|
||||||
{
|
{
|
||||||
audio_output_close(ao);
|
assert(thread.IsDefined());
|
||||||
|
assert(allow_play);
|
||||||
|
|
||||||
assert(!ao->fail_timer.IsDefined());
|
LockCommandWait(AO_COMMAND_KILL);
|
||||||
|
thread.Join();
|
||||||
if (ao->thread.IsDefined()) {
|
}
|
||||||
assert(ao->allow_play);
|
|
||||||
ao_lock_command(ao, AO_COMMAND_KILL);
|
void
|
||||||
ao->thread.Join();
|
AudioOutput::Finish()
|
||||||
}
|
{
|
||||||
|
LockCloseWait();
|
||||||
audio_output_free(ao);
|
|
||||||
|
assert(!fail_timer.IsDefined());
|
||||||
|
|
||||||
|
if (thread.IsDefined())
|
||||||
|
StopThread();
|
||||||
|
|
||||||
|
audio_output_free(this);
|
||||||
}
|
}
|
||||||
|
@ -20,75 +20,6 @@
|
|||||||
#ifndef MPD_OUTPUT_CONTROL_HXX
|
#ifndef MPD_OUTPUT_CONTROL_HXX
|
||||||
#define MPD_OUTPUT_CONTROL_HXX
|
#define MPD_OUTPUT_CONTROL_HXX
|
||||||
|
|
||||||
#include "ReplayGainInfo.hxx"
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
struct AudioOutput;
|
struct AudioOutput;
|
||||||
struct AudioFormat;
|
|
||||||
struct config_param;
|
|
||||||
class MusicPipe;
|
|
||||||
|
|
||||||
void
|
|
||||||
audio_output_set_replay_gain_mode(AudioOutput *ao,
|
|
||||||
ReplayGainMode mode);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enables the device.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
audio_output_enable(AudioOutput *ao);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disables the device.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
audio_output_disable(AudioOutput *ao);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens or closes the device, depending on the "enabled" flag.
|
|
||||||
*
|
|
||||||
* @return true if the device is open
|
|
||||||
*/
|
|
||||||
bool
|
|
||||||
audio_output_update(AudioOutput *ao,
|
|
||||||
AudioFormat audio_format,
|
|
||||||
const MusicPipe &mp);
|
|
||||||
|
|
||||||
void
|
|
||||||
audio_output_play(AudioOutput *ao);
|
|
||||||
|
|
||||||
void
|
|
||||||
audio_output_pause(AudioOutput *ao);
|
|
||||||
|
|
||||||
void
|
|
||||||
audio_output_drain_async(AudioOutput *ao);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear the "allow_play" flag and send the "CANCEL" command
|
|
||||||
* asynchronously. To finish the operation, the caller has to call
|
|
||||||
* audio_output_allow_play().
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
audio_output_cancel(AudioOutput *ao);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the "allow_play" and signal the thread.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
audio_output_allow_play(AudioOutput *ao);
|
|
||||||
|
|
||||||
void
|
|
||||||
audio_output_close(AudioOutput *ao);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes the audio output, but if the "always_on" flag is set, put it
|
|
||||||
* into pause mode instead.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
audio_output_release(AudioOutput *ao);
|
|
||||||
|
|
||||||
void
|
|
||||||
audio_output_finish(AudioOutput *ao);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "OutputThread.hxx"
|
|
||||||
#include "Internal.hxx"
|
#include "Internal.hxx"
|
||||||
#include "OutputAPI.hxx"
|
#include "OutputAPI.hxx"
|
||||||
#include "Domain.hxx"
|
#include "Domain.hxx"
|
||||||
@ -680,11 +679,12 @@ audio_output_task(void *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_output_thread_start(AudioOutput *ao)
|
void
|
||||||
|
AudioOutput::StartThread()
|
||||||
{
|
{
|
||||||
assert(ao->command == AO_COMMAND_NONE);
|
assert(command == AO_COMMAND_NONE);
|
||||||
|
|
||||||
Error error;
|
Error error;
|
||||||
if (!ao->thread.Start(audio_output_task, ao, error))
|
if (!thread.Start(audio_output_task, this, error))
|
||||||
FatalError(error);
|
FatalError(error);
|
||||||
}
|
}
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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_THREAD_HXX
|
|
||||||
#define MPD_OUTPUT_THREAD_HXX
|
|
||||||
|
|
||||||
struct AudioOutput;
|
|
||||||
|
|
||||||
void
|
|
||||||
audio_output_thread_start(AudioOutput *ao);
|
|
||||||
|
|
||||||
#endif
|
|
@ -125,7 +125,7 @@ struct AlsaOutput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Init(const config_param ¶m, Error &error) {
|
bool Init(const config_param ¶m, Error &error) {
|
||||||
return ao_base_init(&base, param, error);
|
return base.Configure(param, error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ struct AoOutput {
|
|||||||
:base(ao_output_plugin) {}
|
:base(ao_output_plugin) {}
|
||||||
|
|
||||||
bool Initialize(const config_param ¶m, Error &error) {
|
bool Initialize(const config_param ¶m, Error &error) {
|
||||||
return ao_base_init(&base, param, error);
|
return base.Configure(param, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Configure(const config_param ¶m, Error &error);
|
bool Configure(const config_param ¶m, Error &error);
|
||||||
|
@ -52,7 +52,7 @@ struct FifoOutput {
|
|||||||
created(false) {}
|
created(false) {}
|
||||||
|
|
||||||
bool Initialize(const config_param ¶m, Error &error) {
|
bool Initialize(const config_param ¶m, Error &error) {
|
||||||
return ao_base_init(&base, param, error);
|
return base.Configure(param, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Create(Error &error);
|
bool Create(Error &error);
|
||||||
|
@ -137,7 +137,7 @@ HttpdOutput::Configure(const config_param ¶m, Error &error)
|
|||||||
inline bool
|
inline bool
|
||||||
HttpdOutput::Init(const config_param ¶m, Error &error)
|
HttpdOutput::Init(const config_param ¶m, Error &error)
|
||||||
{
|
{
|
||||||
return ao_base_init(&base, param, error);
|
return base.Configure(param, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static AudioOutput *
|
static AudioOutput *
|
||||||
|
@ -83,7 +83,7 @@ struct JackOutput {
|
|||||||
:base(jack_output_plugin) {}
|
:base(jack_output_plugin) {}
|
||||||
|
|
||||||
bool Initialize(const config_param ¶m, Error &error_r) {
|
bool Initialize(const config_param ¶m, Error &error_r) {
|
||||||
return ao_base_init(&base, param, error_r);
|
return base.Configure(param, error_r);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ struct NullOutput {
|
|||||||
:base(null_output_plugin) {}
|
:base(null_output_plugin) {}
|
||||||
|
|
||||||
bool Initialize(const config_param ¶m, Error &error) {
|
bool Initialize(const config_param ¶m, Error &error) {
|
||||||
return ao_base_init(&base, param, error);
|
return base.Configure(param, error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ static AudioOutput *
|
|||||||
osx_output_init(const config_param ¶m, Error &error)
|
osx_output_init(const config_param ¶m, Error &error)
|
||||||
{
|
{
|
||||||
OSXOutput *oo = new OSXOutput();
|
OSXOutput *oo = new OSXOutput();
|
||||||
if (!ao_base_init(&oo->base, param, error)) {
|
if (!oo->base.Configure(param, error)) {
|
||||||
delete oo;
|
delete oo;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ struct OpenALOutput {
|
|||||||
:base(openal_output_plugin) {}
|
:base(openal_output_plugin) {}
|
||||||
|
|
||||||
bool Initialize(const config_param ¶m, Error &error_r) {
|
bool Initialize(const config_param ¶m, Error &error_r) {
|
||||||
return ao_base_init(&base, param, error_r);
|
return base.Configure(param, error_r);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ struct OssOutput {
|
|||||||
fd(-1), device(nullptr) {}
|
fd(-1), device(nullptr) {}
|
||||||
|
|
||||||
bool Initialize(const config_param ¶m, Error &error_r) {
|
bool Initialize(const config_param ¶m, Error &error_r) {
|
||||||
return ao_base_init(&base, param, error_r);
|
return base.Configure(param, error_r);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ struct PipeOutput {
|
|||||||
:base(pipe_output_plugin) {}
|
:base(pipe_output_plugin) {}
|
||||||
|
|
||||||
bool Initialize(const config_param ¶m, Error &error) {
|
bool Initialize(const config_param ¶m, Error &error) {
|
||||||
return ao_base_init(&base, param, error);
|
return base.Configure(param, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Configure(const config_param ¶m, Error &error);
|
bool Configure(const config_param ¶m, Error &error);
|
||||||
|
@ -334,7 +334,7 @@ pulse_output_init(const config_param ¶m, Error &error)
|
|||||||
g_setenv("PULSE_PROP_media.role", "music", true);
|
g_setenv("PULSE_PROP_media.role", "music", true);
|
||||||
|
|
||||||
po = new PulseOutput();
|
po = new PulseOutput();
|
||||||
if (!ao_base_init(&po->base, param, error)) {
|
if (!po->base.Configure(param, error)) {
|
||||||
delete po;
|
delete po;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ struct RecorderOutput {
|
|||||||
:base(recorder_output_plugin) {}
|
:base(recorder_output_plugin) {}
|
||||||
|
|
||||||
bool Initialize(const config_param ¶m, Error &error_r) {
|
bool Initialize(const config_param ¶m, Error &error_r) {
|
||||||
return ao_base_init(&base, param, error_r);
|
return base.Configure(param, error_r);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Configure(const config_param ¶m, Error &error);
|
bool Configure(const config_param ¶m, Error &error);
|
||||||
|
@ -58,7 +58,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Initialize(const config_param ¶m, Error &error) {
|
bool Initialize(const config_param ¶m, Error &error) {
|
||||||
return ao_base_init(&base, param, error);
|
return base.Configure(param, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Configure(const config_param ¶m);
|
void Configure(const config_param ¶m);
|
||||||
|
@ -69,7 +69,7 @@ struct ShoutOutput final {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Initialize(const config_param ¶m, Error &error) {
|
bool Initialize(const config_param ¶m, Error &error) {
|
||||||
return ao_base_init(&base, param, error);
|
return base.Configure(param, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Configure(const config_param ¶m, Error &error);
|
bool Configure(const config_param ¶m, Error &error);
|
||||||
|
@ -61,7 +61,7 @@ struct SolarisOutput {
|
|||||||
:base(solaris_output_plugin) {}
|
:base(solaris_output_plugin) {}
|
||||||
|
|
||||||
bool Initialize(const config_param ¶m, Error &error_r) {
|
bool Initialize(const config_param ¶m, Error &error_r) {
|
||||||
return ao_base_init(&base, param, error_r);
|
return base.Configure(param, error_r);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ struct WinmmOutput {
|
|||||||
WinmmBuffer buffers[8];
|
WinmmBuffer buffers[8];
|
||||||
unsigned next_buffer;
|
unsigned next_buffer;
|
||||||
|
|
||||||
WinmmBuffer()
|
WinmmOutput()
|
||||||
:base(winmm_output_plugin) {}
|
:base(winmm_output_plugin) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ static AudioOutput *
|
|||||||
winmm_output_init(const config_param ¶m, Error &error)
|
winmm_output_init(const config_param ¶m, Error &error)
|
||||||
{
|
{
|
||||||
WinmmOutput *wo = new WinmmOutput();
|
WinmmOutput *wo = new WinmmOutput();
|
||||||
if (!ao_base_init(&wo->base, param, error)) {
|
if (!wo->base.Configure(param, error)) {
|
||||||
delete wo;
|
delete wo;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "output/OutputControl.hxx"
|
|
||||||
#include "output/Internal.hxx"
|
#include "output/Internal.hxx"
|
||||||
#include "output/OutputPlugin.hxx"
|
#include "output/OutputPlugin.hxx"
|
||||||
#include "config/ConfigData.hxx"
|
#include "config/ConfigData.hxx"
|
||||||
|
Loading…
Reference in New Issue
Block a user