Commit 98a7c62d authored by Max Kellermann's avatar Max Kellermann

player/Thread: don't send silence if decoder is slow

The output plugin shall decide whether to insert silence or do nothing at all. The ALSA output plugin has already implemented this. Inserting silence is not necessary or helpful for some plugins, and may even hurt them (e.g. "recorder").
parent 859e5926
......@@ -80,14 +80,6 @@ struct MusicChunkInfo {
ReplayGainInfo replay_gain_info;
/**
* A magic value for #replay_gain_serial which omits updating
* the #ReplayGainFilter. This is used by "silence" chunks
* (see PlayerThread::SendSilence()) so they don't affect the
* replay gain.
*/
static constexpr unsigned IGNORE_REPLAY_GAIN = ~0u;
/**
* A serial number for checking if replay gain info has
* changed since the last chunk. The magic value 0 indicates
* that there is no replay gain info available.
......
......@@ -140,8 +140,7 @@ AudioOutputSource::GetChunkData(const MusicChunk &chunk,
replay_gain_filter_set_mode(*current_replay_gain_filter,
replay_gain_mode);
if (chunk.replay_gain_serial != *replay_gain_serial_p &&
chunk.replay_gain_serial != MusicChunk::IGNORE_REPLAY_GAIN) {
if (chunk.replay_gain_serial != *replay_gain_serial_p) {
replay_gain_filter_set_info(*current_replay_gain_filter,
chunk.replay_gain_serial != 0
? &chunk.replay_gain_info
......
......@@ -26,13 +26,11 @@
#include "MusicPipe.hxx"
#include "MusicBuffer.hxx"
#include "MusicChunk.hxx"
#include "pcm/Silence.hxx"
#include "DetachedSong.hxx"
#include "CrossFade.hxx"
#include "Control.hxx"
#include "tag/Tag.hxx"
#include "Idle.hxx"
#include "system/PeriodClock.hxx"
#include "util/Domain.hxx"
#include "thread/Name.hxx"
#include "Log.hxx"
......@@ -157,8 +155,6 @@ class Player {
*/
SongTime pending_seek;
PeriodClock throttle_silence_log;
public:
Player(PlayerControl &_pc, DecoderControl &_dc,
MusicBuffer &_buffer) noexcept
......@@ -305,17 +301,6 @@ private:
*/
bool PlayNextChunk() noexcept;
/**
* Sends a chunk of silence to the audio outputs. This is
* called when there is not enough decoded data in the pipe
* yet, to prevent underruns in the hardware buffers.
*
* The player lock is not held.
*
* @return false on error
*/
bool SendSilence() noexcept;
unsigned UnlockCheckOutputs() noexcept {
const ScopeUnlock unlock(pc.mutex);
return pc.outputs.CheckPipe();
......@@ -551,48 +536,6 @@ Player::CheckDecoderStartup() noexcept
}
bool
Player::SendSilence() noexcept
{
assert(output_open);
assert(play_audio_format.IsDefined());
MusicChunk *chunk = buffer.Allocate();
if (chunk == nullptr) {
/* this is non-fatal, because this means that the
decoder has filled to buffer completely meanwhile;
by ignoring the error, we work around this race
condition */
LogDebug(player_domain, "Failed to allocate silence buffer");
return true;
}
#ifndef NDEBUG
chunk->audio_format = play_audio_format;
#endif
const size_t frame_size = play_audio_format.GetFrameSize();
/* this formula ensures that we don't send
partial frames */
unsigned num_frames = sizeof(chunk->data) / frame_size;
chunk->bit_rate = 0;
chunk->time = SignedSongTime::Negative(); /* undefined time stamp */
chunk->length = num_frames * frame_size;
chunk->replay_gain_serial = MusicChunk::IGNORE_REPLAY_GAIN;
PcmSilence({chunk->data, chunk->length}, play_audio_format.format);
try {
pc.outputs.Play(chunk);
} catch (...) {
LogError(std::current_exception());
buffer.Return(chunk);
return false;
}
return true;
}
bool
Player::SeekDecoder(SongTime seek_time) noexcept
{
assert(song);
......@@ -973,11 +916,8 @@ Player::SongBorder() noexcept
FormatDefault(player_domain, "played \"%s\"", song->GetURI());
throttle_silence_log.Reset();
ReplacePipe(dc.pipe);
pc.outputs.SongBorder();
}
......@@ -1017,15 +957,6 @@ Player::Run() noexcept
!dc.IsIdle()) {
/* not enough decoded buffer space yet */
{
const ScopeUnlock unlock(pc.mutex);
if (!paused && output_open &&
pc.outputs.CheckPipe() < 4 &&
!SendSilence())
break;
}
/* XXX race condition: check decoder again */
dc.WaitForDecoder();
continue;
} else {
......@@ -1115,15 +1046,10 @@ Player::Run() noexcept
}
} else if (output_open) {
/* the decoder is too busy and hasn't provided
new PCM data in time: send silence (if the
output pipe is empty) */
const ScopeUnlock unlock(pc.mutex);
if (throttle_silence_log.CheckUpdate(std::chrono::seconds(5)))
FormatWarning(player_domain, "Decoder is too slow; playing silence to avoid xrun");
new PCM data in time: wait for the
decoder */
if (!SendSilence())
break;
dc.WaitForDecoder();
}
}
......
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