Use an intermediate buffer for writing to the ringbuffer

It doesn't seem as though AudioUnitRender likes being given two buffers to
render/capture samples into segmented memory.
master
Chris Robinson 2022-08-18 10:32:59 -07:00
parent 4115df49cf
commit 19d35a45d7
1 changed files with 11 additions and 26 deletions

View File

@ -548,6 +548,8 @@ struct CoreAudioCapture final : public BackendBase {
SampleConverterPtr mConverter;
al::vector<char> mCaptureData;
RingBufferPtr mRing{nullptr};
DEF_NEWDEL(CoreAudioCapture)
@ -566,43 +568,24 @@ OSStatus CoreAudioCapture::RecordProc(AudioUnitRenderActionFlags *ioActionFlags,
AudioBufferList*) noexcept
{
union {
al::byte _[sizeof(AudioBufferList) + sizeof(AudioBuffer)*2];
al::byte _[maxz(sizeof(AudioBufferList), offsetof(AudioBufferList, mBuffers[1]))];
AudioBufferList list;
} audiobuf{};
auto rec_vec = mRing->getWriteVector();
inNumberFrames = static_cast<UInt32>(minz(inNumberFrames,
rec_vec.first.len+rec_vec.second.len));
audiobuf.list.mNumberBuffers = 1;
audiobuf.list.mBuffers[0].mNumberChannels = mFormat.mChannelsPerFrame;
audiobuf.list.mBuffers[0].mData = mCaptureData.data();
audiobuf.list.mBuffers[0].mDataByteSize = static_cast<UInt32>(mCaptureData.size());
// Fill the ringbuffer's two segments with data from the input device
if(rec_vec.first.len >= inNumberFrames)
{
audiobuf.list.mNumberBuffers = 1;
audiobuf.list.mBuffers[0].mNumberChannels = mFormat.mChannelsPerFrame;
audiobuf.list.mBuffers[0].mData = rec_vec.first.buf;
audiobuf.list.mBuffers[0].mDataByteSize = inNumberFrames * mFormat.mBytesPerFrame;
}
else
{
const auto remaining = static_cast<uint>(inNumberFrames - rec_vec.first.len);
audiobuf.list.mNumberBuffers = 2;
audiobuf.list.mBuffers[0].mNumberChannels = mFormat.mChannelsPerFrame;
audiobuf.list.mBuffers[0].mData = rec_vec.first.buf;
audiobuf.list.mBuffers[0].mDataByteSize = static_cast<UInt32>(rec_vec.first.len) *
mFormat.mBytesPerFrame;
audiobuf.list.mBuffers[1].mNumberChannels = mFormat.mChannelsPerFrame;
audiobuf.list.mBuffers[1].mData = rec_vec.second.buf;
audiobuf.list.mBuffers[1].mDataByteSize = remaining * mFormat.mBytesPerFrame;
}
OSStatus err{AudioUnitRender(mAudioUnit, ioActionFlags, inTimeStamp, inBusNumber,
inNumberFrames, &audiobuf.list)};
if(err != noErr)
{
ERR("AudioUnitRender error: %d\n", err);
ERR("AudioUnitRender capture error: %d\n", err);
return err;
}
mRing->writeAdvance(inNumberFrames);
mRing->write(mCaptureData.data(), inNumberFrames * mFrameSize);
return noErr;
}
@ -814,6 +797,8 @@ void CoreAudioCapture::open(const char *name)
throw al::backend_exception{al::backend_error::DeviceError,
"Could not get input frame count: %u", err};
mCaptureData.resize(outputFrameCount * mFrameSize);
outputFrameCount = static_cast<UInt32>(maxu64(outputFrameCount, FrameCount64));
mRing = RingBuffer::Create(outputFrameCount, mFrameSize, false);