Skip to content

ObrImpl::Process() allocates and frees on the audio thread on every render call #28

Description

@olilarkin

ObrImpl::Process() performs heap allocation and deallocation on every call. Since Process() is the render entry point, it runs on a real-time audio thread in any live playback integration, where malloc/free can block on the allocator lock and are not bounded in time. This is the usual cause of intermittent dropouts that are hard to attribute.

This is independent of any threading or locking concern — it reproduces single-threaded, with head tracking disabled and no concurrent control calls.

Measurement

Built obr with upstream LLVM (RealtimeSanitizer is not in Apple clang) and called Process() from inside a [[clang::nonblocking]] region:

void RenderBlock(ObrImpl* renderer, const AudioBuffer& input,
                 AudioBuffer* output) [[clang::nonblocking]] {
  renderer->Process(input, output);
}

with a single k3OA element, 128-frame buffers, 48 kHz, after one warm-up call outside the checked region. Result, per render call:

4 x malloc, 4 x free

obr_impl.cc:225   AudioBuffer group_output(kNumBinauralChannels, buffer_size_per_channel_);
                    -> audio_buffer.cc:57  vector<float, AlignedAllocator>::resize
                    -> audio_buffer.cc:60  vector<ChannelView>::reserve
obr_impl.cc:240
obr_impl.cc:242   peak_limiter_->Process(...)
                    -> peak_limiter.cc:40, :48, :65

Suggested fix

Both are buffers whose size is known once the DSP is configured, so they can be allocated in InitializeDsp() and reused:

  • hold group_output as a member sized to kNumBinauralChannels x buffer_size_per_channel_, cleared per block instead of constructed per block (AudioBuffer::Clear() is already used elsewhere in Process());
  • give PeakLimiter the same treatment for its internal scratch.

Happy to put a PR together if the approach looks right — I did not want to bundle it with #27, which touches the same function for an unrelated reason.

Environment

main @ aae184e, macOS/arm64, clang 22.1.8, -fsanitize=realtime.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions