Browse Source

Apply OpenAL-soft patch to fix Android audio recording.

kcat/openal-soft@7f1d9725b2df68664e44fbd9944241ab3097a270
kcat/openal-soft@d7367aeee04764ad7595ef3f5de8e01b7a6d93ad
Miku AuahDark 3 years ago
parent
commit
b9964119f5
2 changed files with 52 additions and 83 deletions
  1. 23 66
      libs/openal-soft/alc/backends/oboe.cpp
  2. 29 17
      libs/openal-soft/alc/backends/opensl.cpp

+ 23 - 66
libs/openal-soft/alc/backends/oboe.cpp

@@ -10,6 +10,7 @@
 #include "alnumeric.h"
 #include "alnumeric.h"
 #include "core/device.h"
 #include "core/device.h"
 #include "core/logging.h"
 #include "core/logging.h"
+#include "ringbuffer.h"
 
 
 #include "oboe/Oboe.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} { }
     OboeCapture(DeviceBase *device) : BackendBase{device} { }
 
 
     oboe::ManagedStream mStream;
     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 open(const char *name) override;
     void start() override;
     void start() override;
@@ -203,6 +206,14 @@ struct OboeCapture final : public BackendBase {
     uint availableSamples() override;
     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)
 void OboeCapture::open(const char *name)
 {
 {
     if(!name)
     if(!name)
@@ -217,8 +228,8 @@ void OboeCapture::open(const char *name)
         ->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::High)
         ->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::High)
         ->setChannelConversionAllowed(true)
         ->setChannelConversionAllowed(true)
         ->setFormatConversionAllowed(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
     /* Only use mono or stereo at user request. There's no telling what
      * other counts may be inferred as.
      * 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
     /* FIXME: This really should support UByte, but Oboe doesn't. We'll need to
-     * use a temp buffer and convert.
+     * convert.
      */
      */
     switch(mDevice->FmtType)
     switch(mDevice->FmtType)
     {
     {
@@ -263,22 +274,13 @@ void OboeCapture::open(const char *name)
     if(result != oboe::Result::OK)
     if(result != oboe::Result::OK)
         throw al::backend_exception{al::backend_error::DeviceError, "Failed to create stream: %s",
         throw al::backend_exception{al::backend_error::DeviceError, "Failed to create stream: %s",
             oboe::convertToText(result)};
             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()));
     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;
     mDevice->DeviceName = name;
 }
 }
 
 
@@ -292,23 +294,6 @@ void OboeCapture::start()
 
 
 void OboeCapture::stop()
 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()};
     const oboe::Result result{mStream->stop()};
     if(result != oboe::Result::OK)
     if(result != oboe::Result::OK)
         throw al::backend_exception{al::backend_error::DeviceError, "Failed to stop stream: %s",
         throw al::backend_exception{al::backend_error::DeviceError, "Failed to stop stream: %s",
@@ -316,38 +301,10 @@ void OboeCapture::stop()
 }
 }
 
 
 uint OboeCapture::availableSamples()
 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)
 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
 } // namespace
 
 

+ 29 - 17
libs/openal-soft/alc/backends/opensl.cpp

@@ -878,7 +878,6 @@ void OpenSLCapture::captureSamples(al::byte *buffer, uint samples)
 {
 {
     const uint update_size{mDevice->UpdateSize};
     const uint update_size{mDevice->UpdateSize};
     const uint chunk_size{update_size * mFrameSize};
     const uint chunk_size{update_size * mFrameSize};
-    const auto silence = (mDevice->FmtType == DevFmtUByte) ? al::byte{0x80} : al::byte{0};
 
 
     /* Read the desired samples from the ring buffer then advance its read
     /* Read the desired samples from the ring buffer then advance its read
      * pointer.
      * pointer.
@@ -907,39 +906,52 @@ void OpenSLCapture::captureSamples(al::byte *buffer, uint samples)
 
 
         i += rem;
         i += rem;
     }
     }
-    mRing->readAdvance(adv_count);
 
 
     SLAndroidSimpleBufferQueueItf bufferQueue{};
     SLAndroidSimpleBufferQueueItf bufferQueue{};
-    if LIKELY(mDevice->Connected.load(std::memory_order_acquire))
+    if(likely(mDevice->Connected.load(std::memory_order_acquire)))
     {
     {
         const SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
         const SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
             &bufferQueue)};
             &bufferQueue)};
         PRINTERR(result, "recordObj->GetInterface");
         PRINTERR(result, "recordObj->GetInterface");
-        if UNLIKELY(SL_RESULT_SUCCESS != result)
+        if(unlikely(SL_RESULT_SUCCESS != result))
         {
         {
             mDevice->handleDisconnect("Failed to get capture buffer queue: 0x%08x", result);
             mDevice->handleDisconnect("Failed to get capture buffer queue: 0x%08x", result);
             bufferQueue = nullptr;
             bufferQueue = nullptr;
         }
         }
     }
     }
+    if(unlikely(!bufferQueue) || adv_count == 0)
+        return;
+
+    /* For each buffer chunk that was fully read, queue another writable buffer
+     * chunk to keep the OpenSL queue full. This is rather convulated, as a
+     * result of the ring buffer holding more elements than are writable at a
+     * given time. The end of the write vector increments when the read pointer
+     * advances, which will "expose" a previously unwritable element. So for
+     * every element that we've finished reading, we queue that many elements
+     * from the end of the write vector.
+     */
+    mRing->readAdvance(adv_count);
 
 
-    if LIKELY(bufferQueue)
+    SLresult result{SL_RESULT_SUCCESS};
+    auto wdata = mRing->getWriteVector();
+    if(likely(adv_count > wdata.second.len))
     {
     {
-        SLresult result{SL_RESULT_SUCCESS};
-        auto wdata = mRing->getWriteVector();
-        std::fill_n(wdata.first.buf, wdata.first.len*chunk_size, silence);
-        for(size_t i{0u};i < wdata.first.len && SL_RESULT_SUCCESS == result;i++)
+        auto len1 = std::min(wdata.first.len, adv_count-wdata.second.len);
+        auto buf1 = wdata.first.buf + chunk_size*(wdata.first.len-len1);
+        for(size_t i{0u};i < len1 && SL_RESULT_SUCCESS == result;i++)
         {
         {
-            result = VCALL(bufferQueue,Enqueue)(wdata.first.buf + chunk_size*i, chunk_size);
+            result = VCALL(bufferQueue,Enqueue)(buf1 + chunk_size*i, chunk_size);
             PRINTERR(result, "bufferQueue->Enqueue");
             PRINTERR(result, "bufferQueue->Enqueue");
         }
         }
-        if(wdata.second.len > 0)
+    }
+    if(wdata.second.len > 0)
+    {
+        auto len2 = std::min(wdata.second.len, adv_count);
+        auto buf2 = wdata.second.buf + chunk_size*(wdata.second.len-len2);
+        for(size_t i{0u};i < len2 && SL_RESULT_SUCCESS == result;i++)
         {
         {
-            std::fill_n(wdata.second.buf, wdata.second.len*chunk_size, silence);
-            for(size_t i{0u};i < wdata.second.len && SL_RESULT_SUCCESS == result;i++)
-            {
-                result = VCALL(bufferQueue,Enqueue)(wdata.second.buf + chunk_size*i, chunk_size);
-                PRINTERR(result, "bufferQueue->Enqueue");
-            }
+            result = VCALL(bufferQueue,Enqueue)(buf2 + chunk_size*i, chunk_size);
+            PRINTERR(result, "bufferQueue->Enqueue");
         }
         }
     }
     }
 }
 }