player/Outputs: abstract interface wrapping class MultipleOutputs
This commit is contained in:
parent
c04aafb4e3
commit
c40354bbcb
|
@ -143,6 +143,7 @@ libmpd_a_SOURCES = \
|
|||
src/player/Thread.cxx src/player/Thread.hxx \
|
||||
src/player/Control.cxx src/player/Control.hxx \
|
||||
src/player/Listener.hxx \
|
||||
src/player/Outputs.hxx \
|
||||
src/PlaylistError.cxx src/PlaylistError.hxx \
|
||||
src/PlaylistPrint.cxx src/PlaylistPrint.hxx \
|
||||
src/PlaylistSave.cxx src/PlaylistSave.hxx \
|
||||
|
|
|
@ -315,7 +315,7 @@ MultipleOutputs::ClearTailChunk(const MusicChunk *chunk,
|
|||
}
|
||||
|
||||
unsigned
|
||||
MultipleOutputs::Check() noexcept
|
||||
MultipleOutputs::CheckPipe() noexcept
|
||||
{
|
||||
const MusicChunk *chunk;
|
||||
bool is_tail;
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#define OUTPUT_ALL_H
|
||||
|
||||
#include "Control.hxx"
|
||||
#include "player/Outputs.hxx"
|
||||
#include "AudioFormat.hxx"
|
||||
#include "ReplayGainMode.hxx"
|
||||
#include "Chrono.hxx"
|
||||
|
@ -44,7 +45,7 @@ class AudioOutputClient;
|
|||
struct MusicChunk;
|
||||
struct ReplayGainConfig;
|
||||
|
||||
class MultipleOutputs {
|
||||
class MultipleOutputs final : public PlayerOutputs {
|
||||
MixerListener &mixer_listener;
|
||||
|
||||
std::vector<AudioOutputControl *> outputs;
|
||||
|
@ -115,85 +116,8 @@ public:
|
|||
gcc_pure
|
||||
AudioOutputControl *FindByName(const char *name) noexcept;
|
||||
|
||||
/**
|
||||
* Checks the "enabled" flag of all audio outputs, and if one has
|
||||
* changed, commit the change.
|
||||
*/
|
||||
void EnableDisable();
|
||||
|
||||
/**
|
||||
* Opens all audio outputs which are not disabled.
|
||||
*
|
||||
* Throws #std::runtime_error on error.
|
||||
*
|
||||
* @param audio_format the preferred audio format
|
||||
* @param _buffer the #music_buffer where consumed #MusicChunk objects
|
||||
* should be returned
|
||||
*/
|
||||
void Open(const AudioFormat audio_format, MusicBuffer &_buffer);
|
||||
|
||||
/**
|
||||
* Closes all audio outputs.
|
||||
*/
|
||||
void Close() noexcept;
|
||||
|
||||
/**
|
||||
* Closes all audio outputs. Outputs with the "always_on"
|
||||
* flag are put into pause mode.
|
||||
*/
|
||||
void Release() noexcept;
|
||||
|
||||
void SetReplayGainMode(ReplayGainMode mode) noexcept;
|
||||
|
||||
/**
|
||||
* Enqueue a #MusicChunk object for playing, i.e. pushes it to a
|
||||
* #MusicPipe.
|
||||
*
|
||||
* Throws #std::runtime_error on error (all closed then).
|
||||
*
|
||||
* @param chunk the #MusicChunk object to be played
|
||||
*/
|
||||
void Play(MusicChunk *chunk);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
unsigned Check() noexcept;
|
||||
|
||||
/**
|
||||
* Puts all audio outputs into pause mode. Most implementations will
|
||||
* simply close it then.
|
||||
*/
|
||||
void Pause() noexcept;
|
||||
|
||||
/**
|
||||
* Drain all audio outputs.
|
||||
*/
|
||||
void Drain() noexcept;
|
||||
|
||||
/**
|
||||
* Try to cancel data which may still be in the device's buffers.
|
||||
*/
|
||||
void Cancel() noexcept;
|
||||
|
||||
/**
|
||||
* Indicate that a new song will begin now.
|
||||
*/
|
||||
void SongBorder() noexcept;
|
||||
|
||||
/**
|
||||
* 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
|
||||
SignedSongTime GetElapsedTime() const noexcept {
|
||||
return elapsed_time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the average volume of all available mixers (range
|
||||
* 0..100). Returns -1 if no mixer can be queried.
|
||||
|
@ -259,6 +183,22 @@ private:
|
|||
* reference.
|
||||
*/
|
||||
void ClearTailChunk(const MusicChunk *chunk, bool *locked) noexcept;
|
||||
|
||||
/* virtual methods from class PlayerOutputs */
|
||||
void EnableDisable() override;
|
||||
void Open(const AudioFormat audio_format,
|
||||
MusicBuffer &_buffer) override;
|
||||
void Close() noexcept override;
|
||||
void Release() noexcept override;
|
||||
void Play(MusicChunk *chunk) override;
|
||||
unsigned CheckPipe() noexcept override;
|
||||
void Pause() noexcept override;
|
||||
void Drain() noexcept override;
|
||||
void Cancel() noexcept override;
|
||||
void SongBorder() noexcept override;
|
||||
SignedSongTime GetElapsedTime() const noexcept override {
|
||||
return elapsed_time;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue