Apply OpenAL-soft patch to fix Android audio recording.

kcat/openal-soft@7f1d9725b2
kcat/openal-soft@d7367aeee0
This commit is contained in:
Miku AuahDark
2022-06-18 22:48:23 +08:00
parent 83fd21b130
commit b9964119f5
2 changed files with 52 additions and 83 deletions
+23 -66
View File
@@ -10,6 +10,7 @@
#include "alnumeric.h"
#include "core/device.h"
#include "core/logging.h"
#include "ringbuffer.h"
#include "oboe/Oboe.h"
@@ -188,13 +189,15 @@ void OboePlayback::stop()
}
struct OboeCapture final : public BackendBase {
struct OboeCapture final : public BackendBase, public oboe::AudioStreamCallback {
OboeCapture(DeviceBase *device) : BackendBase{device} { }
oboe::ManagedStream mStream;
std::vector<al::byte> mSamples;
uint mLastAvail{0u};
RingBufferPtr mRing{nullptr};
oboe::DataCallbackResult onAudioReady(oboe::AudioStream *oboeStream, void *audioData,
int32_t numFrames) override;
void open(const char *name) override;
void start() override;
@@ -203,6 +206,14 @@ struct OboeCapture final : public BackendBase {
uint availableSamples() override;
};
oboe::DataCallbackResult OboeCapture::onAudioReady(oboe::AudioStream*, void *audioData,
int32_t numFrames)
{
mRing->write(audioData, static_cast<uint32_t>(numFrames));
return oboe::DataCallbackResult::Continue;
}
void OboeCapture::open(const char *name)
{
if(!name)
@@ -217,8 +228,8 @@ void OboeCapture::open(const char *name)
->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::High)
->setChannelConversionAllowed(true)
->setFormatConversionAllowed(true)
->setBufferCapacityInFrames(static_cast<int32_t>(mDevice->BufferSize))
->setSampleRate(static_cast<int32_t>(mDevice->Frequency));
->setSampleRate(static_cast<int32_t>(mDevice->Frequency))
->setCallback(this);
/* Only use mono or stereo at user request. There's no telling what
* other counts may be inferred as.
*/
@@ -240,7 +251,7 @@ void OboeCapture::open(const char *name)
}
/* FIXME: This really should support UByte, but Oboe doesn't. We'll need to
* use a temp buffer and convert.
* convert.
*/
switch(mDevice->FmtType)
{
@@ -263,22 +274,13 @@ void OboeCapture::open(const char *name)
if(result != oboe::Result::OK)
throw al::backend_exception{al::backend_error::DeviceError, "Failed to create stream: %s",
oboe::convertToText(result)};
if(static_cast<int32_t>(mDevice->BufferSize) > mStream->getBufferCapacityInFrames())
throw al::backend_exception{al::backend_error::DeviceError,
"Buffer size too large (%u > %d)", mDevice->BufferSize,
mStream->getBufferCapacityInFrames()};
auto buffer_result = mStream->setBufferSizeInFrames(static_cast<int32_t>(mDevice->BufferSize));
if(!buffer_result)
throw al::backend_exception{al::backend_error::DeviceError,
"Failed to set buffer size: %s", oboe::convertToText(buffer_result.error())};
else if(buffer_result.value() < static_cast<int32_t>(mDevice->BufferSize))
throw al::backend_exception{al::backend_error::DeviceError,
"Failed to set large enough buffer size (%u > %d)", mDevice->BufferSize,
buffer_result.value()};
mDevice->BufferSize = static_cast<uint>(buffer_result.value());
TRACE("Got stream with properties:\n%s", oboe::convertToText(mStream.get()));
/* Ensure a minimum ringbuffer size of 100ms. */
mRing = RingBuffer::Create(maxu(mDevice->BufferSize, mDevice->Frequency/10),
static_cast<uint32_t>(mStream->getBytesPerFrame()), false);
mDevice->DeviceName = name;
}
@@ -292,23 +294,6 @@ 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",
@@ -316,38 +301,10 @@ void OboeCapture::stop()
}
uint OboeCapture::availableSamples()
{
/* Keep track of the max available frame count, to ensure it doesn't go
* backwards.
*/
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;
}
{ return static_cast<uint>(mRing->readSpace()); }
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)
std::fill_n(buffer + got*frame_size, (samples-got)*frame_size, al::byte{});
mLastAvail = std::max(mLastAvail, samples) - samples;
}
{ mRing->read(buffer, samples); }
} // namespace