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:
parent
ec456fc57c
commit
684bd9153e
@ -404,8 +404,29 @@ public:
|
|||||||
gcc_pure
|
gcc_pure
|
||||||
bool LockIsChunkConsumed(const MusicChunk &chunk) const noexcept;
|
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 {
|
void ClearTailChunk(const MusicChunk &chunk) noexcept {
|
||||||
|
if (!IsOpen())
|
||||||
|
return;
|
||||||
|
|
||||||
source.ClearTailChunk(chunk);
|
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;
|
void LockPlay() noexcept;
|
||||||
|
@ -271,35 +271,10 @@ MultipleOutputs::IsChunkConsumed(const MusicChunk *chunk) const noexcept
|
|||||||
return true;
|
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
|
unsigned
|
||||||
MultipleOutputs::CheckPipe() noexcept
|
MultipleOutputs::CheckPipe() noexcept
|
||||||
{
|
{
|
||||||
const MusicChunk *chunk;
|
const MusicChunk *chunk;
|
||||||
bool locked[outputs.size()];
|
|
||||||
|
|
||||||
assert(pipe != nullptr);
|
assert(pipe != nullptr);
|
||||||
|
|
||||||
@ -320,18 +295,18 @@ MultipleOutputs::CheckPipe() noexcept
|
|||||||
if (is_tail)
|
if (is_tail)
|
||||||
/* this is the tail of the pipe - clear the
|
/* this is the tail of the pipe - clear the
|
||||||
chunk reference in all outputs */
|
chunk reference in all outputs */
|
||||||
ClearTailChunk(chunk, locked);
|
for (const auto &ao : outputs)
|
||||||
|
ao->LockClearTailChunk(*chunk);
|
||||||
|
|
||||||
/* remove the chunk from the pipe */
|
/* remove the chunk from the pipe */
|
||||||
const auto shifted = pipe->Shift();
|
const auto shifted = pipe->Shift();
|
||||||
assert(shifted.get() == chunk);
|
assert(shifted.get() == chunk);
|
||||||
|
|
||||||
if (is_tail)
|
if (is_tail)
|
||||||
/* unlock all audio outputs which were locked
|
/* resume playback which has been suspended by
|
||||||
by clear_tail_chunk() */
|
LockClearTailChunk() */
|
||||||
for (unsigned i = 0, n = outputs.size(); i != n; ++i)
|
for (const auto &ao : outputs)
|
||||||
if (locked[i])
|
ao->LockAllowPlay();
|
||||||
outputs[i]->mutex.unlock();
|
|
||||||
|
|
||||||
/* chunk is automatically returned to the buffer by
|
/* chunk is automatically returned to the buffer by
|
||||||
~MusicChunkPtr() */
|
~MusicChunkPtr() */
|
||||||
|
@ -171,13 +171,6 @@ private:
|
|||||||
*/
|
*/
|
||||||
bool IsChunkConsumed(const MusicChunk *chunk) const noexcept;
|
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 */
|
/* virtual methods from class PlayerOutputs */
|
||||||
void EnableDisable() override;
|
void EnableDisable() override;
|
||||||
void Open(const AudioFormat audio_format) override;
|
void Open(const AudioFormat audio_format) override;
|
||||||
|
Loading…
Reference in New Issue
Block a user