aboutsummaryrefslogtreecommitdiffstats
path: root/alc/backends
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2022-04-06 21:10:46 -0700
committerChris Robinson <[email protected]>2022-04-06 21:53:26 -0700
commita42fe862c54bcaa4cfe39cfcf4de8a4c0f3eab14 (patch)
treeec15b5c53fb8c0002b8bc04c97fedcbcad98b239 /alc/backends
parent6a9fe1e2c1c06b6bc04c3b78e2a9f69dd7a5ec6e (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.cpp49
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