diff options
author | Chris Robinson <[email protected]> | 2022-04-06 21:10:46 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2022-04-06 21:53:26 -0700 |
commit | a42fe862c54bcaa4cfe39cfcf4de8a4c0f3eab14 (patch) | |
tree | ec15b5c53fb8c0002b8bc04c97fedcbcad98b239 /alc/backends | |
parent | 6a9fe1e2c1c06b6bc04c3b78e2a9f69dd7a5ec6e (diff) |
Keep track of uncaptured samples with the Oboe backend
Stopping Oboe capture drops uncaptured samples, whereas OpenAL keeps them. Also
make sure the reported available count doesn't go backwards without reading.
Diffstat (limited to 'alc/backends')
-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 |