Commit 4657a3bd authored by Max Kellermann's avatar Max Kellermann

output: move functions into the AudioOutput struct

parent cb7366f4
...@@ -963,9 +963,9 @@ OUTPUT_API_SRC = \ ...@@ -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, ...@@ -147,14 +147,11 @@ audio_output_load_mixer(AudioOutput *ao,
} }
bool bool
ao_base_init(AudioOutput *ao, AudioOutput::Configure(const config_param &param, Error &error)
const config_param &param, 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, ...@@ -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, ...@@ -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, ...@@ -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 @@ ...@@ -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 { ...@@ -266,6 +267,106 @@ struct AudioOutput {
AudioOutput(const AudioOutputPlugin &_plugin); AudioOutput(const AudioOutputPlugin &_plugin);
~AudioOutput(); ~AudioOutput();
bool Configure(const config_param &param, 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 { ...@@ -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 &param, audio_output_new(const config_param &param,
PlayerControl &pc, PlayerControl &pc,
Error &error); Error &error);
bool
ao_base_init(AudioOutput *ao,
const config_param &param, Error &error);
void void
audio_output_free(AudioOutput *ao); audio_output_free(AudioOutput *ao);
......
...@@ -21,7 +21,6 @@ ...@@ -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() ...@@ -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() ...@@ -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 ...@@ -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 ...@@ -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() ...@@ -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 ...@@ -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) ...@@ -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() ...@@ -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 ...@@ -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() ...@@ -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 ...@@ -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 ...@@ -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);
......
/* /*
* 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 @@ ...@@ -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; ...@@ -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;
cond.signal();
} }
/** void
* Sends a command to the #AudioOutput object and waits for AudioOutput::CommandWait(audio_output_command cmd)
* 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); CommandAsync(cmd);
ao_command_wait(ao); WaitForCommand();
} }
/** void
* Lock the #AudioOutput object and execute the command AudioOutput::LockCommandWait(audio_output_command cmd)
* synchronously.
*/
static void
ao_lock_command(AudioOutput *ao, enum audio_output_command cmd)
{ {
const ScopeLock protect(ao->mutex); const ScopeLock protect(mutex);
ao_command(ao, cmd); CommandWait(cmd);
} }
void void
audio_output_set_replay_gain_mode(AudioOutput *ao, AudioOutput::SetReplayGainMode(ReplayGainMode mode)
ReplayGainMode mode)
{ {
if (ao->replay_gain_filter != nullptr) if (replay_gain_filter != nullptr)
replay_gain_filter_set_mode(ao->replay_gain_filter, mode); replay_gain_filter_set_mode(replay_gain_filter, mode);
if (ao->other_replay_gain_filter != nullptr) if (other_replay_gain_filter != nullptr)
replay_gain_filter_set_mode(ao->other_replay_gain_filter, mode); replay_gain_filter_set_mode(other_replay_gain_filter, mode);
} }
void void
audio_output_enable(AudioOutput *ao) AudioOutput::LockEnableWait()
{ {
if (!ao->thread.IsDefined()) { if (!thread.IsDefined()) {
if (ao->plugin.enable == nullptr) { 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, ...@@ -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()) { void
assert(ao->allow_play); AudioOutput::Finish()
ao_lock_command(ao, AO_COMMAND_KILL); {
ao->thread.Join(); LockCloseWait();
}
assert(!fail_timer.IsDefined());
if (thread.IsDefined())
StopThread();
audio_output_free(ao); audio_output_free(this);
} }
...@@ -20,75 +20,6 @@ ...@@ -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 @@ ...@@ -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) ...@@ -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);
} }
/*
* 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 { ...@@ -125,7 +125,7 @@ struct AlsaOutput {
} }
bool Init(const config_param &param, Error &error) { bool Init(const config_param &param, Error &error) {
return ao_base_init(&base, param, error); return base.Configure(param, error);
} }
}; };
......
...@@ -46,7 +46,7 @@ struct AoOutput { ...@@ -46,7 +46,7 @@ struct AoOutput {
:base(ao_output_plugin) {} :base(ao_output_plugin) {}
bool Initialize(const config_param &param, Error &error) { bool Initialize(const config_param &param, Error &error) {
return ao_base_init(&base, param, error); return base.Configure(param, error);
} }
bool Configure(const config_param &param, Error &error); bool Configure(const config_param &param, Error &error);
......
...@@ -52,7 +52,7 @@ struct FifoOutput { ...@@ -52,7 +52,7 @@ struct FifoOutput {
created(false) {} created(false) {}
bool Initialize(const config_param &param, Error &error) { bool Initialize(const config_param &param, 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 &param, Error &error) ...@@ -137,7 +137,7 @@ HttpdOutput::Configure(const config_param &param, Error &error)
inline bool inline bool
HttpdOutput::Init(const config_param &param, Error &error) HttpdOutput::Init(const config_param &param, Error &error)
{ {
return ao_base_init(&base, param, error); return base.Configure(param, error);
} }
static AudioOutput * static AudioOutput *
......
...@@ -83,7 +83,7 @@ struct JackOutput { ...@@ -83,7 +83,7 @@ struct JackOutput {
:base(jack_output_plugin) {} :base(jack_output_plugin) {}
bool Initialize(const config_param &param, Error &error_r) { bool Initialize(const config_param &param, Error &error_r) {
return ao_base_init(&base, param, error_r); return base.Configure(param, error_r);
} }
}; };
......
...@@ -33,7 +33,7 @@ struct NullOutput { ...@@ -33,7 +33,7 @@ struct NullOutput {
:base(null_output_plugin) {} :base(null_output_plugin) {}
bool Initialize(const config_param &param, Error &error) { bool Initialize(const config_param &param, Error &error) {
return ao_base_init(&base, param, error); return base.Configure(param, error);
} }
}; };
......
...@@ -84,7 +84,7 @@ static AudioOutput * ...@@ -84,7 +84,7 @@ static AudioOutput *
osx_output_init(const config_param &param, Error &error) osx_output_init(const config_param &param, 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 { ...@@ -52,7 +52,7 @@ struct OpenALOutput {
:base(openal_output_plugin) {} :base(openal_output_plugin) {}
bool Initialize(const config_param &param, Error &error_r) { bool Initialize(const config_param &param, Error &error_r) {
return ao_base_init(&base, param, error_r); return base.Configure(param, error_r);
} }
}; };
......
...@@ -83,7 +83,7 @@ struct OssOutput { ...@@ -83,7 +83,7 @@ struct OssOutput {
fd(-1), device(nullptr) {} fd(-1), device(nullptr) {}
bool Initialize(const config_param &param, Error &error_r) { bool Initialize(const config_param &param, Error &error_r) {
return ao_base_init(&base, param, error_r); return base.Configure(param, error_r);
} }
}; };
......
...@@ -38,7 +38,7 @@ struct PipeOutput { ...@@ -38,7 +38,7 @@ struct PipeOutput {
:base(pipe_output_plugin) {} :base(pipe_output_plugin) {}
bool Initialize(const config_param &param, Error &error) { bool Initialize(const config_param &param, Error &error) {
return ao_base_init(&base, param, error); return base.Configure(param, error);
} }
bool Configure(const config_param &param, Error &error); bool Configure(const config_param &param, Error &error);
......
...@@ -334,7 +334,7 @@ pulse_output_init(const config_param &param, Error &error) ...@@ -334,7 +334,7 @@ pulse_output_init(const config_param &param, 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 { ...@@ -61,7 +61,7 @@ struct RecorderOutput {
:base(recorder_output_plugin) {} :base(recorder_output_plugin) {}
bool Initialize(const config_param &param, Error &error_r) { bool Initialize(const config_param &param, Error &error_r) {
return ao_base_init(&base, param, error_r); return base.Configure(param, error_r);
} }
bool Configure(const config_param &param, Error &error); bool Configure(const config_param &param, Error &error);
......
...@@ -58,7 +58,7 @@ public: ...@@ -58,7 +58,7 @@ public:
} }
bool Initialize(const config_param &param, Error &error) { bool Initialize(const config_param &param, Error &error) {
return ao_base_init(&base, param, error); return base.Configure(param, error);
} }
void Configure(const config_param &param); void Configure(const config_param &param);
......
...@@ -69,7 +69,7 @@ struct ShoutOutput final { ...@@ -69,7 +69,7 @@ struct ShoutOutput final {
} }
bool Initialize(const config_param &param, Error &error) { bool Initialize(const config_param &param, Error &error) {
return ao_base_init(&base, param, error); return base.Configure(param, error);
} }
bool Configure(const config_param &param, Error &error); bool Configure(const config_param &param, Error &error);
......
...@@ -61,7 +61,7 @@ struct SolarisOutput { ...@@ -61,7 +61,7 @@ struct SolarisOutput {
:base(solaris_output_plugin) {} :base(solaris_output_plugin) {}
bool Initialize(const config_param &param, Error &error_r) { bool Initialize(const config_param &param, Error &error_r) {
return ao_base_init(&base, param, error_r); return base.Configure(param, error_r);
} }
}; };
......
...@@ -52,7 +52,7 @@ struct WinmmOutput { ...@@ -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 * ...@@ -115,7 +115,7 @@ static AudioOutput *
winmm_output_init(const config_param &param, Error &error) winmm_output_init(const config_param &param, 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 @@ ...@@ -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"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment