Silence the PCM buffer if no chunk is available

This commit is contained in:
badaix 2021-02-03 22:58:21 +01:00
parent 147e4e9b7e
commit 168bc3f98b
7 changed files with 31 additions and 11 deletions

View file

@ -108,7 +108,7 @@ void CoreAudioPlayer::playerCallback(AudioQueueRef queue, AudioQueueBufferRef bu
/// TODO: sometimes this bufferedMS or AudioTimeStamp wraps around 1s (i.e. we're 1s out of sync (behind)) and recovers later on /// TODO: sometimes this bufferedMS or AudioTimeStamp wraps around 1s (i.e. we're 1s out of sync (behind)) and recovers later on
chronos::usec delay(bufferedMs * 1000); chronos::usec delay(bufferedMs * 1000);
char* buffer = (char*)bufferRef->mAudioData; char* buffer = (char*)bufferRef->mAudioData;
if (!pubStream_->getPlayerChunk(buffer, delay, frames_)) if (!pubStream_->getPlayerChunkOrSilence(buffer, delay, frames_))
{ {
if (chronos::getTickCount() - lastChunkTick > 5000) if (chronos::getTickCount() - lastChunkTick > 5000)
{ {
@ -117,7 +117,6 @@ void CoreAudioPlayer::playerCallback(AudioQueueRef queue, AudioQueueBufferRef bu
return; return;
} }
// LOG(INFO, LOG_TAG) << "Failed to get chunk. Playing silence.\n"; // LOG(INFO, LOG_TAG) << "Failed to get chunk. Playing silence.\n";
memset(buffer, 0, buff_size_);
} }
else else
{ {

View file

@ -85,20 +85,21 @@ void FilePlayer::requestAudio()
if (buffer_.size() < needed) if (buffer_.size() < needed)
buffer_.resize(needed); buffer_.resize(needed);
if (!stream_->getPlayerChunk(buffer_.data(), 10ms, numFrames)) if (!stream_->getPlayerChunkOrSilence(buffer_.data(), 10ms, numFrames))
{ {
// LOG(INFO, LOG_TAG) << "Failed to get chunk. Playing silence.\n"; // LOG(INFO, LOG_TAG) << "Failed to get chunk. Playing silence.\n";
memset(buffer_.data(), 0, needed);
} }
else else
{ {
adjustVolume(static_cast<char*>(buffer_.data()), numFrames); adjustVolume(static_cast<char*>(buffer_.data()), numFrames);
} }
if (file_) if (file_)
{ {
fwrite(buffer_.data(), 1, needed, file_.get()); fwrite(buffer_.data(), 1, needed, file_.get());
fflush(file_.get()); fflush(file_.get());
} }
loop(); loop();
} }

View file

@ -152,10 +152,9 @@ oboe::DataCallbackResult OboePlayer::onAudioReady(oboe::AudioStream* /*oboeStrea
// LOG(INFO, LOG_TAG) << "getCurrentOutputLatencyMillis: " << output_latency << ", frames: " << numFrames << "\n"; // LOG(INFO, LOG_TAG) << "getCurrentOutputLatencyMillis: " << output_latency << ", frames: " << numFrames << "\n";
chronos::usec delay(static_cast<int>(output_latency * 1000.)); chronos::usec delay(static_cast<int>(output_latency * 1000.));
if (!stream_->getPlayerChunk(audioData, delay, numFrames)) if (!stream_->getPlayerChunkOrSilence(audioData, delay, numFrames))
{ {
// LOG(INFO, LOG_TAG) << "Failed to get chunk. Playing silence.\n"; // LOG(INFO, LOG_TAG) << "Failed to get chunk. Playing silence.\n";
memset(audioData, 0, numFrames * stream_->getFormat().frameSize());
} }
else else
{ {

View file

@ -78,10 +78,9 @@ void OpenslPlayer::playerCallback(SLAndroidSimpleBufferQueueItf bq)
return; return;
chronos::usec delay(ms_ * 1000); chronos::usec delay(ms_ * 1000);
if (!pubStream_->getPlayerChunk(buffer[curBuffer], delay, frames_)) if (!pubStream_->getPlayerChunkOrSilence(buffer[curBuffer], delay, frames_))
{ {
// LOG(INFO, LOG_TAG) << "Failed to get chunk. Playing silence.\n"; // LOG(INFO, LOG_TAG) << "Failed to get chunk. Playing silence.\n";
memset(buffer[curBuffer], 0, buff_size);
} }
else else
{ {

View file

@ -299,10 +299,9 @@ void PulsePlayer::writeCallback(pa_stream* stream, size_t nbytes)
if (buffer_.size() < nbytes) if (buffer_.size() < nbytes)
buffer_.resize(nbytes); buffer_.resize(nbytes);
// LOG(TRACE, LOG_TAG) << "writeCallback latency " << usec << " us, frames: " << numFrames << "\n"; // LOG(TRACE, LOG_TAG) << "writeCallback latency " << usec << " us, frames: " << numFrames << "\n";
if (!stream_->getPlayerChunk(buffer_.data(), std::chrono::microseconds(usec), numFrames)) if (!stream_->getPlayerChunkOrSilence(buffer_.data(), std::chrono::microseconds(usec), numFrames))
{ {
// LOG(INFO, LOG_TAG) << "Failed to get chunk. Playing silence.\n"; // LOG(TRACE, LOG_TAG) << "Failed to get chunk. Playing silence.\n";
memset(buffer_.data(), 0, buffer_.size());
} }
else else
{ {

View file

@ -24,6 +24,7 @@
#include "common/aixlog.hpp" #include "common/aixlog.hpp"
#include "common/snap_exception.hpp" #include "common/snap_exception.hpp"
#include "common/str_compat.hpp" #include "common/str_compat.hpp"
#include "common/utils/logging.hpp"
#include "time_provider.hpp" #include "time_provider.hpp"
#include <cmath> #include <cmath>
#include <iostream> #include <iostream>
@ -441,3 +442,16 @@ bool Stream::getPlayerChunk(void* outputBuffer, const cs::usec& outputBufferDacT
return false; return false;
} }
} }
bool Stream::getPlayerChunkOrSilence(void* outputBuffer, const chronos::usec& outputBufferDacTime, uint32_t frames)
{
bool result = getPlayerChunk(outputBuffer, outputBufferDacTime, frames);
if (!result)
{
static utils::logging::TimeConditional cond(1s);
LOG(DEBUG, LOG_TAG) << cond << "Failed to get chunk, returning silence\n";
getSilentPlayerChunk(outputBuffer, frames);
}
return result;
}

View file

@ -48,8 +48,17 @@ public:
/// Get PCM data, which will be played out in "outputBufferDacTime" time /// Get PCM data, which will be played out in "outputBufferDacTime" time
/// frame = (num_channels) * (1 sample in bytes) = (2 channels) * (2 bytes (16 bits) per sample) = 4 bytes (32 bits) /// frame = (num_channels) * (1 sample in bytes) = (2 channels) * (2 bytes (16 bits) per sample) = 4 bytes (32 bits)
/// @param[out] outputBuffer the buffer to be filled with PCM data
/// @param outputBufferDacTime the duration until the PCM chunk will be audible
/// @param frames the number of requested frames to be copied into outputBuffer
/// @return true if a chunk was available and successfully copied to outputBuffer
bool getPlayerChunk(void* outputBuffer, const chronos::usec& outputBufferDacTime, uint32_t frames); bool getPlayerChunk(void* outputBuffer, const chronos::usec& outputBufferDacTime, uint32_t frames);
/// Try to get a player chunk and fill the buffer with silence if it fails
/// @sa getPlayerChunk
/// @return true if a chunk was available and successfully copied to outputBuffer, else false and outputBuffer is filled with silence
bool getPlayerChunkOrSilence(void* outputBuffer, const chronos::usec& outputBufferDacTime, uint32_t frames);
/// "Server buffer": playout latency, e.g. 1000ms /// "Server buffer": playout latency, e.g. 1000ms
void setBufferLen(size_t bufferLenMs); void setBufferLen(size_t bufferLenMs);