Avoid copying of the PCM stream

This commit is contained in:
badaix 2020-09-27 11:06:00 +02:00
parent fcb40f325a
commit 888e19a8a4
3 changed files with 43 additions and 19 deletions

View file

@ -57,6 +57,16 @@ Resampler::Resampler(const SampleFormat& in_format, const SampleFormat& out_form
} }
bool Resampler::resamplingNeeded() const
{
#ifdef HAS_SOXR
return soxr_ != nullptr;
#else
return false;
#endif
}
// std::shared_ptr<msg::PcmChunk> Resampler::resample(std::shared_ptr<msg::PcmChunk> chunk, chronos::usec duration) // std::shared_ptr<msg::PcmChunk> Resampler::resample(std::shared_ptr<msg::PcmChunk> chunk, chronos::usec duration)
// { // {
// auto resampled_chunk = resample(chunk); // auto resampled_chunk = resample(chunk);
@ -85,43 +95,44 @@ Resampler::Resampler(const SampleFormat& in_format, const SampleFormat& out_form
// // } // // }
// } // }
shared_ptr<msg::PcmChunk> Resampler::resample(shared_ptr<msg::PcmChunk> chunk)
std::shared_ptr<msg::PcmChunk> Resampler::resample(const msg::PcmChunk& chunk)
{ {
#ifndef HAS_SOXR #ifndef HAS_SOXR
return chunk; return std::make_shared<msg::PcmChunk>(chunk);
#else #else
if (soxr_ == nullptr) if (!resamplingNeeded())
{ {
return chunk; return std::make_shared<msg::PcmChunk>(chunk);
} }
else else
{ {
if (in_format_.bits() == 24) if (in_format_.bits() == 24)
{ {
// sox expects 32 bit input, shift 8 bits left // sox expects 32 bit input, shift 8 bits left
int32_t* frames = (int32_t*)chunk->payload; int32_t* frames = (int32_t*)chunk.payload;
for (size_t n = 0; n < chunk->getSampleCount(); ++n) for (size_t n = 0; n < chunk.getSampleCount(); ++n)
frames[n] = frames[n] << 8; frames[n] = frames[n] << 8;
} }
size_t idone; size_t idone;
size_t odone; size_t odone;
auto resample_buffer_framesize = resample_buffer_.size() / out_format_.frameSize(); auto resample_buffer_framesize = resample_buffer_.size() / out_format_.frameSize();
auto error = soxr_process(soxr_, chunk->payload, chunk->getFrameCount(), &idone, resample_buffer_.data(), resample_buffer_framesize, &odone); auto error = soxr_process(soxr_, chunk.payload, chunk.getFrameCount(), &idone, resample_buffer_.data(), resample_buffer_framesize, &odone);
if (error) if (error)
{ {
LOG(ERROR, LOG_TAG) << "Error soxr_process: " << error << "\n"; LOG(ERROR, LOG_TAG) << "Error soxr_process: " << error << "\n";
} }
else else
{ {
LOG(TRACE, LOG_TAG) << "Resample idone: " << idone << "/" << chunk->getFrameCount() << ", odone: " << odone << "/" LOG(TRACE, LOG_TAG) << "Resample idone: " << idone << "/" << chunk.getFrameCount() << ", odone: " << odone << "/"
<< resample_buffer_.size() / out_format_.frameSize() << ", delay: " << soxr_delay(soxr_) << "\n"; << resample_buffer_.size() / out_format_.frameSize() << ", delay: " << soxr_delay(soxr_) << "\n";
// some data has been resampled (odone frames) and some is still in the pipe (soxr_delay frames) // some data has been resampled (odone frames) and some is still in the pipe (soxr_delay frames)
if (odone > 0) if (odone > 0)
{ {
// get the resampled ts from the input ts // get the resampled ts from the input ts
auto input_end_ts = chunk->start() + chunk->duration<std::chrono::microseconds>(); auto input_end_ts = chunk.start() + chunk.duration<std::chrono::microseconds>();
double resampled_ms = (odone + soxr_delay(soxr_)) / out_format_.msRate(); double resampled_ms = (odone + soxr_delay(soxr_)) / out_format_.msRate();
auto resampled_start = input_end_ts - std::chrono::microseconds(static_cast<int>(resampled_ms * 1000.)); auto resampled_start = input_end_ts - std::chrono::microseconds(static_cast<int>(resampled_ms * 1000.));
@ -172,6 +183,23 @@ shared_ptr<msg::PcmChunk> Resampler::resample(shared_ptr<msg::PcmChunk> chunk)
} }
shared_ptr<msg::PcmChunk> Resampler::resample(shared_ptr<msg::PcmChunk> chunk)
{
#ifndef HAS_SOXR
return chunk;
#else
if (!resamplingNeeded())
{
return chunk;
}
else
{
return resample(*chunk);
}
#endif
}
Resampler::~Resampler() Resampler::~Resampler()
{ {
#ifdef HAS_SOXR #ifdef HAS_SOXR

View file

@ -36,6 +36,8 @@ public:
// std::shared_ptr<msg::PcmChunk> resample(std::shared_ptr<msg::PcmChunk> chunk, chronos::usec duration); // std::shared_ptr<msg::PcmChunk> resample(std::shared_ptr<msg::PcmChunk> chunk, chronos::usec duration);
std::shared_ptr<msg::PcmChunk> resample(std::shared_ptr<msg::PcmChunk> chunk); std::shared_ptr<msg::PcmChunk> resample(std::shared_ptr<msg::PcmChunk> chunk);
std::shared_ptr<msg::PcmChunk> resample(const msg::PcmChunk& chunk);
bool resamplingNeeded() const;
private: private:
std::vector<char> resample_buffer_; std::vector<char> resample_buffer_;

View file

@ -62,10 +62,7 @@ MetaStream::MetaStream(PcmListener* pcmListener, std::vector<std::shared_ptr<Pcm
if (!streams_.empty()) if (!streams_.empty())
{ {
active_stream_ = streams_.front(); active_stream_ = streams_.front();
if ((sampleFormat_.rate() != active_stream_->getSampleFormat().rate()) || (sampleFormat_.bits() != active_stream_->getSampleFormat().bits()))
resampler_ = make_unique<Resampler>(active_stream_->getSampleFormat(), sampleFormat_); resampler_ = make_unique<Resampler>(active_stream_->getSampleFormat(), sampleFormat_);
else
resampler_ = nullptr;
} }
} }
@ -112,10 +109,7 @@ void MetaStream::onStateChanged(const PcmStream* pcmStream, ReaderState state)
if (active_stream_ != stream) if (active_stream_ != stream)
{ {
active_stream_ = stream; active_stream_ = stream;
if ((sampleFormat_.rate() != active_stream_->getSampleFormat().rate()) || (sampleFormat_.bits() != active_stream_->getSampleFormat().bits()))
resampler_ = make_unique<Resampler>(active_stream_->getSampleFormat(), sampleFormat_); resampler_ = make_unique<Resampler>(active_stream_->getSampleFormat(), sampleFormat_);
else
resampler_ = nullptr;
} }
setState(ReaderState::kPlaying); setState(ReaderState::kPlaying);
@ -164,9 +158,9 @@ void MetaStream::onChunkRead(const PcmStream* pcmStream, const msg::PcmChunk& ch
} }
} }
if (resampler_) if (resampler_ && resampler_->resamplingNeeded())
{ {
auto resampled_chunk = resampler_->resample(std::make_shared<msg::PcmChunk>(chunk)); auto resampled_chunk = resampler_->resample(chunk);
if (resampled_chunk) if (resampled_chunk)
chunkRead(*resampled_chunk); chunkRead(*resampled_chunk);
} }