diff options
-rw-r--r-- | alc/backends/oboe.cpp | 49 |
1 files changed, 41 insertions, 8 deletions
diff --git a/alc/backends/oboe.cpp b/alc/backends/oboe.cpp index aefda974..38f048cb 100644 --- a/alc/backends/oboe.cpp +++ b/alc/backends/oboe.cpp @@ -193,6 +193,9 @@ struct OboeCapture final : public BackendBase { oboe::ManagedStream mStream; + std::vector<al::byte> mSamples; + uint mLastAvail{0u}; + void open(const char *name) override; void start() override; void stop() override; @@ -289,6 +292,23 @@ void OboeCapture::start() void OboeCapture::stop() { + /* Capture any unread samples before stopping. Oboe drops whatever's left + * in the stream. + */ + if(auto availres = mStream->getAvailableFrames()) + { + const auto avail = std::max(static_cast<uint>(availres.value()), mLastAvail); + const size_t frame_size{static_cast<uint32_t>(mStream->getBytesPerFrame())}; + const size_t pos{mSamples.size()}; + mSamples.resize(pos + avail*frame_size); + + auto result = mStream->read(&mSamples[pos], availres.value(), 0); + uint got{bool{result} ? static_cast<uint>(result.value()) : 0u}; + if(got < avail) + std::fill_n(&mSamples[pos + got*frame_size], (avail-got)*frame_size, al::byte{}); + mLastAvail = 0; + } + const oboe::Result result{mStream->stop()}; if(result != oboe::Result::OK) throw al::backend_exception{al::backend_error::DeviceError, "Failed to stop stream: %s", @@ -297,23 +317,36 @@ void OboeCapture::stop() uint OboeCapture::availableSamples() { - auto result = mStream->getAvailableFrames(); - /* FIXME: This shouldn't report less samples than have been previously - * reported and not captured. + /* Keep track of the max available frame count, to ensure it doesn't go + * backwards. */ - if(!result) return 0; - return static_cast<uint>(result.value()); + if(auto result = mStream->getAvailableFrames()) + mLastAvail = std::max(static_cast<uint>(result.value()), mLastAvail); + + const auto frame_size = static_cast<uint32_t>(mStream->getBytesPerFrame()); + return static_cast<uint>(mSamples.size()/frame_size) + mLastAvail; } void OboeCapture::captureSamples(al::byte *buffer, uint samples) { + const auto frame_size = static_cast<uint>(mStream->getBytesPerFrame()); + if(const size_t storelen{mSamples.size()}) + { + const auto instore = static_cast<uint>(storelen / frame_size); + const uint tocopy{std::min(samples, instore) * frame_size}; + std::copy_n(mSamples.begin(), tocopy, buffer); + mSamples.erase(mSamples.begin(), mSamples.begin() + tocopy); + + buffer += tocopy; + samples -= tocopy/frame_size; + if(!samples) return; + } + auto result = mStream->read(buffer, static_cast<int32_t>(samples), 0); uint got{bool{result} ? static_cast<uint>(result.value()) : 0u}; if(got < samples) - { - auto frame_size = static_cast<uint>(mStream->getBytesPerFrame()); std::fill_n(buffer + got*frame_size, (samples-got)*frame_size, al::byte{}); - } + mLastAvail = std::max(mLastAvail, samples) - samples; } } // namespace |