diff --git a/client/player/coreaudio_player.cpp b/client/player/coreaudio_player.cpp index bf521265..9be159d6 100644 --- a/client/player/coreaudio_player.cpp +++ b/client/player/coreaudio_player.cpp @@ -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 chronos::usec delay(bufferedMs * 1000); char* buffer = (char*)bufferRef->mAudioData; - if (!pubStream_->getPlayerChunk(buffer, delay, frames_)) + if (!pubStream_->getPlayerChunkOrSilence(buffer, delay, frames_)) { if (chronos::getTickCount() - lastChunkTick > 5000) { @@ -117,7 +117,6 @@ void CoreAudioPlayer::playerCallback(AudioQueueRef queue, AudioQueueBufferRef bu return; } // LOG(INFO, LOG_TAG) << "Failed to get chunk. Playing silence.\n"; - memset(buffer, 0, buff_size_); } else { diff --git a/client/player/file_player.cpp b/client/player/file_player.cpp index b2d11830..7d944156 100644 --- a/client/player/file_player.cpp +++ b/client/player/file_player.cpp @@ -85,20 +85,21 @@ void FilePlayer::requestAudio() if (buffer_.size() < 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"; - memset(buffer_.data(), 0, needed); } else { adjustVolume(static_cast(buffer_.data()), numFrames); } + if (file_) { fwrite(buffer_.data(), 1, needed, file_.get()); fflush(file_.get()); } + loop(); } diff --git a/client/player/oboe_player.cpp b/client/player/oboe_player.cpp index 6f9ec348..dff57d1d 100644 --- a/client/player/oboe_player.cpp +++ b/client/player/oboe_player.cpp @@ -152,10 +152,9 @@ oboe::DataCallbackResult OboePlayer::onAudioReady(oboe::AudioStream* /*oboeStrea // LOG(INFO, LOG_TAG) << "getCurrentOutputLatencyMillis: " << output_latency << ", frames: " << numFrames << "\n"; chronos::usec delay(static_cast(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"; - memset(audioData, 0, numFrames * stream_->getFormat().frameSize()); } else { diff --git a/client/player/opensl_player.cpp b/client/player/opensl_player.cpp index 833c8565..cb1ac57b 100644 --- a/client/player/opensl_player.cpp +++ b/client/player/opensl_player.cpp @@ -78,10 +78,9 @@ void OpenslPlayer::playerCallback(SLAndroidSimpleBufferQueueItf bq) return; 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"; - memset(buffer[curBuffer], 0, buff_size); } else { diff --git a/client/player/pulse_player.cpp b/client/player/pulse_player.cpp index 28a407e1..f737bf2e 100644 --- a/client/player/pulse_player.cpp +++ b/client/player/pulse_player.cpp @@ -299,10 +299,9 @@ void PulsePlayer::writeCallback(pa_stream* stream, size_t nbytes) if (buffer_.size() < nbytes) buffer_.resize(nbytes); // 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"; - memset(buffer_.data(), 0, buffer_.size()); + // LOG(TRACE, LOG_TAG) << "Failed to get chunk. Playing silence.\n"; } else { diff --git a/client/stream.cpp b/client/stream.cpp index 772f41f4..c50f9657 100644 --- a/client/stream.cpp +++ b/client/stream.cpp @@ -24,6 +24,7 @@ #include "common/aixlog.hpp" #include "common/snap_exception.hpp" #include "common/str_compat.hpp" +#include "common/utils/logging.hpp" #include "time_provider.hpp" #include #include @@ -441,3 +442,16 @@ bool Stream::getPlayerChunk(void* outputBuffer, const cs::usec& outputBufferDacT 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; +} diff --git a/client/stream.hpp b/client/stream.hpp index e37c2c44..503b5213 100644 --- a/client/stream.hpp +++ b/client/stream.hpp @@ -48,8 +48,17 @@ public: /// 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) + /// @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); + /// 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 void setBufferLen(size_t bufferLenMs);