output/MultipleOutputs: simplify locking in CheckPipe()

Instead of keeping all open outputs locked, let ClearTailChunk() stall
playback until MultipleOutputs::CheckPipe() has updated the MusicPipe.
This commit is contained in:
Max Kellermann 2019-04-26 18:12:27 +02:00
parent ec456fc57c
commit 684bd9153e
3 changed files with 27 additions and 38 deletions

View File

@ -404,8 +404,29 @@ public:
gcc_pure
bool LockIsChunkConsumed(const MusicChunk &chunk) const noexcept;
/**
* There's only one chunk left in the pipe (#pipe), and all
* audio outputs have consumed it already. Clear the
* reference.
*
* This stalls playback to give the caller a chance to shift
* the #MusicPipe without getting disturbed; after this,
* LockAllowPlay() must be called to resume playback.
*/
void ClearTailChunk(const MusicChunk &chunk) noexcept {
if (!IsOpen())
return;
source.ClearTailChunk(chunk);
allow_play = false;
}
/**
* Locking wrapper for ClearTailChunk().
*/
void LockClearTailChunk(const MusicChunk &chunk) noexcept {
const std::lock_guard<Mutex> lock(mutex);
ClearTailChunk(chunk);
}
void LockPlay() noexcept;

View File

@ -271,35 +271,10 @@ MultipleOutputs::IsChunkConsumed(const MusicChunk *chunk) const noexcept
return true;
}
inline void
MultipleOutputs::ClearTailChunk(const MusicChunk *chunk,
bool *locked) noexcept
{
assert(chunk->next == nullptr);
assert(pipe->Contains(chunk));
for (unsigned i = 0, n = outputs.size(); i != n; ++i) {
auto &ao = *outputs[i];
/* this mutex will be unlocked by the caller when it's
ready */
ao.mutex.lock();
locked[i] = ao.IsOpen();
if (!locked[i]) {
ao.mutex.unlock();
continue;
}
ao.ClearTailChunk(*chunk);
}
}
unsigned
MultipleOutputs::CheckPipe() noexcept
{
const MusicChunk *chunk;
bool locked[outputs.size()];
assert(pipe != nullptr);
@ -320,18 +295,18 @@ MultipleOutputs::CheckPipe() noexcept
if (is_tail)
/* this is the tail of the pipe - clear the
chunk reference in all outputs */
ClearTailChunk(chunk, locked);
for (const auto &ao : outputs)
ao->LockClearTailChunk(*chunk);
/* remove the chunk from the pipe */
const auto shifted = pipe->Shift();
assert(shifted.get() == chunk);
if (is_tail)
/* unlock all audio outputs which were locked
by clear_tail_chunk() */
for (unsigned i = 0, n = outputs.size(); i != n; ++i)
if (locked[i])
outputs[i]->mutex.unlock();
/* resume playback which has been suspended by
LockClearTailChunk() */
for (const auto &ao : outputs)
ao->LockAllowPlay();
/* chunk is automatically returned to the buffer by
~MusicChunkPtr() */

View File

@ -171,13 +171,6 @@ private:
*/
bool IsChunkConsumed(const MusicChunk *chunk) const noexcept;
/**
* There's only one chunk left in the pipe (#pipe), and all
* audio outputs have consumed it already. Clear the
* reference.
*/
void ClearTailChunk(const MusicChunk *chunk, bool *locked) noexcept;
/* virtual methods from class PlayerOutputs */
void EnableDisable() override;
void Open(const AudioFormat audio_format) override;