summaryrefslogtreecommitdiff
path: root/src/player
diff options
context:
space:
mode:
Diffstat (limited to 'src/player')
-rw-r--r--src/player/Control.cxx8
-rw-r--r--src/player/Control.hxx6
-rw-r--r--src/player/Outputs.hxx117
-rw-r--r--src/player/Thread.cxx8
4 files changed, 128 insertions, 11 deletions
diff --git a/src/player/Control.cxx b/src/player/Control.cxx
index b9786c031..2522e2a41 100644
--- a/src/player/Control.cxx
+++ b/src/player/Control.cxx
@@ -19,16 +19,16 @@
#include "config.h"
#include "Control.hxx"
+#include "Outputs.hxx"
#include "Idle.hxx"
#include "DetachedSong.hxx"
-#include "output/MultipleOutputs.hxx"
#include <algorithm>
#include <assert.h>
PlayerControl::PlayerControl(PlayerListener &_listener,
- MultipleOutputs &_outputs,
+ PlayerOutputs &_outputs,
unsigned _buffer_chunks,
unsigned _buffered_before_play,
AudioFormat _configured_audio_format,
@@ -50,10 +50,10 @@ PlayerControl::~PlayerControl() noexcept
bool
PlayerControl::WaitOutputConsumed(unsigned threshold) noexcept
{
- bool result = outputs.Check() < threshold;
+ bool result = outputs.CheckPipe() < threshold;
if (!result && command == PlayerCommand::NONE) {
Wait();
- result = outputs.Check() < threshold;
+ result = outputs.CheckPipe() < threshold;
}
return result;
diff --git a/src/player/Control.hxx b/src/player/Control.hxx
index 073bbac90..4a2c84079 100644
--- a/src/player/Control.hxx
+++ b/src/player/Control.hxx
@@ -36,7 +36,7 @@
#include <stdint.h>
class PlayerListener;
-class MultipleOutputs;
+class PlayerOutputs;
class DetachedSong;
enum class PlayerState : uint8_t {
@@ -108,7 +108,7 @@ struct player_status {
struct PlayerControl final : AudioOutputClient {
PlayerListener &listener;
- MultipleOutputs &outputs;
+ PlayerOutputs &outputs;
const unsigned buffer_chunks;
@@ -223,7 +223,7 @@ struct PlayerControl final : AudioOutputClient {
double total_play_time = 0;
PlayerControl(PlayerListener &_listener,
- MultipleOutputs &_outputs,
+ PlayerOutputs &_outputs,
unsigned buffer_chunks,
unsigned buffered_before_play,
AudioFormat _configured_audio_format,
diff --git a/src/player/Outputs.hxx b/src/player/Outputs.hxx
new file mode 100644
index 000000000..9b896ce5d
--- /dev/null
+++ b/src/player/Outputs.hxx
@@ -0,0 +1,117 @@
+/*
+ * 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_PLAYER_OUTPUT_INTERFACE_HXX
+#define MPD_PLAYER_OUTPUT_INTERFACE_HXX
+
+#include "Chrono.hxx"
+#include "Compiler.h"
+
+struct AudioFormat;
+struct MusicChunk;
+class MusicBuffer;
+
+/**
+ * An interface for the player thread to control all outputs. This
+ * interface is implemented only by #MultipleOutputs, and exists only
+ * to decouple the player code from the output code, to be able to
+ * unit-test the player code.
+ */
+class PlayerOutputs {
+public:
+ /**
+ * Checks the "enabled" flag of all audio outputs, and if one has
+ * changed, commit the change.
+ *
+ * Throws on error.
+ */
+ virtual void EnableDisable() = 0;
+
+ /**
+ * Opens all audio outputs which are not disabled.
+ *
+ * Throws on error.
+ *
+ * @param audio_format the preferred audio format
+ * @param buffer the #MusicBuffer where consumed #MusicChunk
+ * objects should be returned
+ */
+ virtual void Open(const AudioFormat audio_format,
+ MusicBuffer &buffer) = 0;
+
+ /**
+ * Closes all audio outputs.
+ */
+ virtual void Close() noexcept = 0;
+
+ /**
+ * Closes all audio outputs. Outputs with the "always_on"
+ * flag are put into pause mode.
+ */
+ virtual void Release() noexcept = 0;
+
+ /**
+ * Enqueue a #MusicChunk object for playing, i.e. pushes it to a
+ * #MusicPipe.
+ *
+ * Throws on error (all closed then).
+ *
+ * @param chunk the #MusicChunk object to be played
+ */
+ virtual void Play(MusicChunk *chunk) = 0;
+
+ /**
+ * Checks if the output devices have drained their music pipe, and
+ * returns the consumed music chunks to the #music_buffer.
+ *
+ * @return the number of chunks to play left in the #MusicPipe
+ */
+ virtual unsigned CheckPipe() noexcept = 0;
+
+ /**
+ * Puts all audio outputs into pause mode. Most implementations will
+ * simply close it then.
+ */
+ virtual void Pause() noexcept = 0;
+
+ /**
+ * Drain all audio outputs.
+ */
+ virtual void Drain() noexcept = 0;
+
+ /**
+ * Try to cancel data which may still be in the device's buffers.
+ */
+ virtual void Cancel() noexcept = 0;
+
+ /**
+ * Indicate that a new song will begin now.
+ */
+ virtual void SongBorder() noexcept = 0;
+
+ /**
+ * Returns the "elapsed_time" stamp of the most recently finished
+ * chunk. A negative value is returned when no chunk has been
+ * finished yet.
+ */
+ gcc_pure
+ virtual SignedSongTime GetElapsedTime() const noexcept = 0;
+};
+
+#endif
diff --git a/src/player/Thread.cxx b/src/player/Thread.cxx
index 0525a81c5..f9d0cd204 100644
--- a/src/player/Thread.cxx
+++ b/src/player/Thread.cxx
@@ -19,6 +19,7 @@
#include "config.h"
#include "Thread.hxx"
+#include "Outputs.hxx"
#include "Listener.hxx"
#include "decoder/DecoderThread.hxx"
#include "decoder/DecoderControl.hxx"
@@ -29,7 +30,6 @@
#include "DetachedSong.hxx"
#include "CrossFade.hxx"
#include "Control.hxx"
-#include "output/MultipleOutputs.hxx"
#include "tag/Tag.hxx"
#include "Idle.hxx"
#include "system/PeriodClock.hxx"
@@ -334,7 +334,7 @@ private:
unsigned UnlockCheckOutputs() noexcept {
const ScopeUnlock unlock(pc.mutex);
- return pc.outputs.Check();
+ return pc.outputs.CheckPipe();
}
/**
@@ -750,7 +750,7 @@ Player::ProcessCommand() noexcept
case PlayerCommand::REFRESH:
if (output_open && !paused) {
const ScopeUnlock unlock(pc.mutex);
- pc.outputs.Check();
+ pc.outputs.CheckPipe();
}
pc.elapsed_time = !pc.outputs.GetElapsedTime().IsNegative()
@@ -1004,7 +1004,7 @@ Player::Run() noexcept
{
const ScopeUnlock unlock(pc.mutex);
if (!paused && output_open &&
- pc.outputs.Check() < 4 &&
+ pc.outputs.CheckPipe() < 4 &&
!SendSilence())
break;
}