Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@

IOSRecorderCallback::~IOSRecorderCallback()
{
// Stop new audio-thread enqueues, then join the worker, before releasing
// the ObjC fields the worker reads in taskOffloaderFunction. The
// unique_ptr<TaskOffloader> member would otherwise be destroyed only
// after this body returns, leaving a window where the worker can
// dereference already-nil ObjC fields.
isInitialized_.store(false, std::memory_order_release);
offloader_.reset();

@autoreleasepool {
converter_ = nil;
bufferFormat_ = nil;
Expand Down Expand Up @@ -104,7 +112,22 @@
/// This method should be called from the JS thread only.
void IOSRecorderCallback::cleanup()
{
// Stop new audio-thread enqueues, then join the worker, before releasing
// the ObjC fields the worker reads in taskOffloaderFunction. Releasing
// the fields first leaves a window where the worker can dereference a
// now-nil converterInputBuffer_ / bufferFormat_ / converter_.
//
// ~TaskOffloader signals shutdown and joins; it does NOT drain queued
// items. Frames sitting in the SPSC channel at this point are dropped.
// Frames the worker had already pushed into circularBuffer_ before being
// joined remain present and are flushed below.
isInitialized_.store(false, std::memory_order_release);
offloader_.reset();

@autoreleasepool {
// Flush frames already accumulated in circularBuffer_ to preserve the
// documented behaviour that remaining buffered callback data is emitted
// on cleanup.
if (circularBuffer_[0]->getNumberOfAvailableFrames() > 0) {
emitAudioData(true);
}
Expand All @@ -118,7 +141,6 @@
for (size_t i = 0; i < channelCount_; ++i) {
circularBuffer_[i]->zero();
}
offloader_.reset();
}
}

Expand Down
Loading