Repository: WebKit/WebKit
Pull request #45544: MediaRecorderPrivateEncoder shouldn't use lock on audio thread.
Author: login: jyavenard
Labels: name: Media
description: Bugs related to the HTML 5 Media elements.
Created: 2025-05-17T11:31:30Z | Merged: 2025-05-19T11:08:36Z

#### 61d17594f7e3620871c08ea2b55a49008951acdd
<pre>
MediaRecorderPrivateEncoder shouldn&apos;t use lock on audio thread.
<a href="https://bugs.webkit.org/show_bug.cgi?id=293174">https://bugs.webkit.org/show_bug.cgi?id=293174</a>
<a href="https://rdar.apple.com/151516146">rdar://151516146</a>

Reviewed by Youenn Fablet.

Make access to the ringbuffers lockless.
Whenever the audio format changes, we have to create a new ringbuffer.
We now send the new ringbuffer to the queue alongside an Id to be able
to determine when the old ringbuffer is no longer in use and can be safely
removed from the dequeue, doing it all on the audio thread.
The lock was a low contention one, being only ever taken on the audio thread.
The only time it would be taken on the workqueue was if the audio format changed.

There&apos;s still a memory allocation required whenever the audio format change
(including on the first sample received).

Covered by existing tests, no change in observable behaviour

Canonical link: <a href="https://commits.webkit.org/295090@main">https://commits.webkit.org/295090@main</a>
</pre>
<!--EWS-Status-Bubble-Start-->
https://github.com/WebKit/WebKit/commit/bd80c39200fe122d1539bf8a721ff7893228b68b

| Misc | iOS, visionOS, tvOS & watchOS  | macOS  | Linux |  Windows |
| ----- | ---------------------- | ------- |  ----- |  --------- |
| [✅ 🧪 style](https://ews-build.webkit.org/#/builders/38/builds/104079 "Passed style check") | [✅ 🛠 ios](https://ews-build.webkit.org/#/builders/131/builds/23783 "Built successfully") | [✅ 🛠 mac](https://ews-build.webkit.org/#/builders/138/builds/14103 "Built successfully") | [✅ 🛠 wpe](https://ews-build.webkit.org/#/builders/5/builds/109275 "Built successfully") | [✅ 🛠 win](https://ews-build.webkit.org/#/builders/59/builds/54747 "Built successfully") 
| [✅ 🧪 bindings](https://ews-build.webkit.org/#/builders/9/builds/106119 "Passed tests") | [✅ 🛠 ios-sim](https://ews-build.webkit.org/#/builders/130/builds/24150 "Built successfully") | [✅ 🛠 mac-AS-debug](https://ews-build.webkit.org/#/builders/123/builds/32327 "Built successfully") | [✅ 🧪 wpe-wk2](https://ews-build.webkit.org/#/builders/34/builds/79067 "Passed tests") | [⏳ 🧪 win-tests](https://ews-build.webkit.org/#/builders/Win-Tests-EWS "Waiting to run tests") 
| [✅ 🧪 webkitperl](https://ews-build.webkit.org/#/builders/11/builds/107085 "Passed tests") | [✅ 🧪 ios-wk2](https://ews-build.webkit.org/#/builders/132/builds/18756 "Passed tests") | [✅ 🧪 api-mac](https://ews-build.webkit.org/#/builders/18/builds/93887 "Passed tests") | [❌ 🧪 api-wpe](https://ews-build.webkit.org/#/builders/41/builds/59394 "Found 1 new API test failure: /WPE/TestCookieManager:/webkit/WebKitCookieManager/persistent-storage (failure)") | 
| | [✅ 🧪 ios-wk2-wpt](https://ews-build.webkit.org/#/builders/133/builds/18562 "Passed tests") | [✅ 🧪 mac-wk1](https://ews-build.webkit.org/#/builders/135/builds/11933 "Passed tests") | [✅ 🛠 wpe-cairo](https://ews-build.webkit.org/#/builders/65/builds/54107 "Built successfully") | 
| | [✅ 🧪 api-ios](https://ews-build.webkit.org/#/builders/13/builds/88279 "Passed tests") | [✅ 🧪 mac-wk2](https://ews-build.webkit.org/#/builders/136/builds/11991 "Passed tests") | [✅ 🛠 gtk](https://ews-build.webkit.org/#/builders/2/builds/111661 "Built successfully") | 
| | [✅ 🛠 vision](https://ews-build.webkit.org/#/builders/128/builds/31235 "Built successfully") | [✅ 🧪 mac-AS-debug-wk2](https://ews-build.webkit.org/#/builders/122/builds/23028 "Passed tests") | [✅ 🧪 gtk-wk2](https://ews-build.webkit.org/#/builders/1/builds/88078 "Passed tests") | 
| | [✅ 🛠 vision-sim](https://ews-build.webkit.org/#/builders/121/builds/31599 "Built successfully") | [✅ 🧪 mac-wk2-stress](https://ews-build.webkit.org/#/builders/8/builds/90082 "Passed tests") | [❌ 🧪 api-gtk](https://ews-build.webkit.org/#/builders/21/builds/87735 "Found 99 new API test failures: /WebKitGTK/TestInputMethodContext:/webkit/WebKitInputMethodContext/invalid-sequence, /WebKitGTK/TestDownloads:/webkit/Downloads/blob-download, /WebKitGTK/TestUIClient:/webkit/WebKitWebView/mouse-target, /TestWebKit:WebKit.UserMediaBasic, /WebKitGTK/TestWebProcessExtensions:/webkit/WebKitWebProcessExtension/dom-input-element-is-user-edited, /WebKitGTK/TestDownloads:/webkit/Downloads/contex-menu-download-actions, /WebKitGTK/TestInputMethodContext:/webkit/WebKitInputMethodContext/cancel-sequence, /WebKitGTK/TestWebKitWebView:/webkit/WebKitWebView/is-playing-audio, /WebKitGTK/TestWebKitWebView:/webkit/WebKitWebView/page-visibility, /WebKitGTK/TestOptionMenu:/webkit/WebKitWebView/option-menu-select ... (failure)") | 
| [✅ 🛠 🧪 merge](https://ews-build.webkit.org/#/builders/19/builds/22329 "Built successfully and passed tests") | [✅ 🧪 vision-wk2](https://ews-build.webkit.org/#/builders/126/builds/32615 "Passed tests") | [✅ 🧪 mac-intel-wk2](https://ews-build.webkit.org/#/builders/137/builds/10368 "Passed tests") | [✅ 🛠 playstation](https://ews-build.webkit.org/#/builders/134/builds/25683 "Built successfully") | 
| | [✅ 🛠 tv](https://ews-build.webkit.org/#/builders/127/builds/31164 "Built successfully") | [✅ 🛠 mac-safer-cpp](https://ews-build.webkit.org/#/builders/120/builds/36476 "Built successfully") | | 
| | [✅ 🛠 tv-sim](https://ews-build.webkit.org/#/builders/125/builds/30958 "Built successfully") | | | 
| | [✅ 🛠 watch](https://ews-build.webkit.org/#/builders/129/builds/34294 "Built successfully") | | | 
| | [✅ 🛠 watch-sim](https://ews-build.webkit.org/#/builders/124/builds/32518 "Built successfully") | | | 
<!--EWS-Status-Bubble-End-->


Diff:
diff --git a/Source/WebCore/SaferCPPExpectations/ForwardDeclCheckerExpectations b/Source/WebCore/SaferCPPExpectations/ForwardDeclCheckerExpectations
index 6c37aacac5ed..14d671df7259 100644
--- a/Source/WebCore/SaferCPPExpectations/ForwardDeclCheckerExpectations
+++ b/Source/WebCore/SaferCPPExpectations/ForwardDeclCheckerExpectations
@@ -113,7 +113,6 @@ platform/graphics/angle/GraphicsContextGLANGLE.cpp
 platform/graphics/ca/PlatformCALayer.h
 platform/graphics/ca/TileController.cpp
 platform/graphics/mac/LegacyDisplayRefreshMonitorMac.h
-platform/mediarecorder/MediaRecorderPrivateEncoder.h
 platform/mediastream/libwebrtc/LibWebRTCDav1dDecoder.cpp
 platform/mediastream/mac/CoreAudioSharedUnit.h
 platform/network/cocoa/CredentialCocoa.h
diff --git a/Source/WebCore/platform/mediarecorder/MediaRecorderPrivateEncoder.cpp b/Source/WebCore/platform/mediarecorder/MediaRecorderPrivateEncoder.cpp
index f572a88ab5e9..82123e6c5032 100644
--- a/Source/WebCore/platform/mediarecorder/MediaRecorderPrivateEncoder.cpp
+++ b/Source/WebCore/platform/mediarecorder/MediaRecorderPrivateEncoder.cpp
@@ -291,7 +291,8 @@ void MediaRecorderPrivateEncoder::appendAudioSampleBuffer(const PlatformAudioDat
         m_currentStreamDescription = toCAAudioStreamDescription(description);
         addRingBuffer(description);
         m_currentAudioSampleCount = 0;
-    }
+    } else
+        clearRingBuffersIfPossible();
 
     auto currentAudioTime = m_currentAudioTime;
     m_lastEnqueuedAudioTimeUs = m_currentAudioTime.toMicroseconds();
@@ -309,10 +310,14 @@ void MediaRecorderPrivateEncoder::appendAudioSampleBuffer(const PlatformAudioDat
     m_currentAudioSampleCount += sampleCount;
 }
 
-void MediaRecorderPrivateEncoder::audioSamplesDescriptionChanged(const AudioStreamBasicDescription& description)
+void MediaRecorderPrivateEncoder::audioSamplesDescriptionChanged(const AudioStreamBasicDescription& description, InProcessCARingBuffer* newRingBuffer, size_t ringBufferId)
 {
     assertIsCurrent(queueSingleton());
 
+    if (!newRingBuffer) {
+        m_hadError = true;
+        return;
+    }
     if (!m_originalOutputDescription) {
         if (m_audioCodec != kAudioFormatLinearPCM) {
             AudioStreamBasicDescription outputDescription = { };
@@ -350,42 +355,39 @@ void MediaRecorderPrivateEncoder::audioSamplesDescriptionChanged(const AudioStre
         return;
     }
 
-    updateCurrentRingBufferIfNeeded();
+    m_currentRingBuffer = newRingBuffer;
+    m_currentRingBufferId = ringBufferId;
 }
 
 void MediaRecorderPrivateEncoder::addRingBuffer(const AudioStreamDescription& description)
 {
     auto asbd = *std::get<const AudioStreamBasicDescription*>(description.platformDescription().description);
-    Locker locker { m_ringBuffersLock };
-    m_ringBuffers.append(InProcessCARingBuffer::allocate(asbd, description.sampleRate() * 2)); // allocate 2s of buffer.
-    queueSingleton().dispatch([weakThis = ThreadSafeWeakPtr { *this }, description = asbd] {
+    m_ringBuffers.append(std::make_pair(InProcessCARingBuffer::allocate(asbd, description.sampleRate() * 2), ++m_lastRingBufferId)); // allocate 2s of buffer.
+    queueSingleton().dispatch([weakThis = ThreadSafeWeakPtr { *this }, description = asbd, newRingBuffer = m_ringBuffers.last().first.get(), lastRingBufferId = m_lastRingBufferId] {
         if (RefPtr protectedThis = weakThis.get())
-            protectedThis->audioSamplesDescriptionChanged(description);
+            protectedThis->audioSamplesDescriptionChanged(description, newRingBuffer, lastRingBufferId);
     });
 }
 
 void MediaRecorderPrivateEncoder::writeDataToRingBuffer(AudioBufferList* list, size_t sampleCount, size_t totalSampleCount)
 {
-    Locker locker { m_ringBuffersLock };
-    if (m_ringBuffers.isEmpty() || !m_ringBuffers.last())
+    ASSERT(!m_ringBuffers.isEmpty());
+    if (!m_ringBuffers.last().first)
         return;
-    m_ringBuffers.last()->store(list, sampleCount, totalSampleCount);
+    m_ringBuffers.last().first->store(list, sampleCount, totalSampleCount);
 }
 
-void MediaRecorderPrivateEncoder::updateCurrentRingBufferIfNeeded()
+void MediaRecorderPrivateEncoder::clearRingBuffersIfPossible()
 {
-    assertIsCurrent(queueSingleton());
-
-    Locker locker { m_ringBuffersLock };
-    if (m_currentRingBuffer) {
-        ASSERT(m_ringBuffers.size() > 1);
-        m_ringBuffers.removeFirst();
-    }
-    m_currentRingBuffer = m_ringBuffers.first().get();
-    if (!m_currentRingBuffer) {
-        RELEASE_LOG_ERROR(MediaStream, "MediaRecorderPrivateEncoder::audioSamplesDescriptionChanged: out of memory error occurred");
-        m_hadError = true;
-    }
+    if (m_ringBuffers.size() == 1)
+        return;
+    size_t currentRingBufferId = m_currentRingBufferId;
+    while (m_ringBuffers.size() > 1) {
+        if (m_ringBuffers.first().second < currentRingBufferId)
+            m_ringBuffers.removeFirst();
+        else
+            break;
+    };
 }
 
 void MediaRecorderPrivateEncoder::audioSamplesAvailable(const MediaTime& time, size_t sampleCount, size_t totalSampleCount)
@@ -885,11 +887,6 @@ void MediaRecorderPrivateEncoder::stopRecording()
 
         m_isPaused = false;
 
-        {
-            Locker locker { m_ringBuffersLock };
-            m_ringBuffers.clear();
-        }
-
         RefPtr converter = audioConverter();
         if (!converter)
             return;
diff --git a/Source/WebCore/platform/mediarecorder/MediaRecorderPrivateEncoder.h b/Source/WebCore/platform/mediarecorder/MediaRecorderPrivateEncoder.h
index 21c8b4fb9ad2..4ddde301c027 100644
--- a/Source/WebCore/platform/mediarecorder/MediaRecorderPrivateEncoder.h
+++ b/Source/WebCore/platform/mediarecorder/MediaRecorderPrivateEncoder.h
@@ -103,7 +103,7 @@ class MediaRecorderPrivateEncoder final : public ThreadSafeRefCountedAndCanMakeT
 
     void generateMIMEType();
 
-    void audioSamplesDescriptionChanged(const AudioStreamBasicDescription&);
+    void audioSamplesDescriptionChanged(const AudioStreamBasicDescription&, InProcessCARingBuffer*, size_t);
     void audioSamplesAvailable(const MediaTime&, size_t, size_t);
     RefPtr<AudioSampleBufferConverter> audioConverter() const;
     void enqueueCompressedAudioSampleBuffers();
@@ -126,7 +126,7 @@ class MediaRecorderPrivateEncoder final : public ThreadSafeRefCountedAndCanMakeT
 
     void addRingBuffer(const AudioStreamDescription&);
     void writeDataToRingBuffer(AudioBufferList*, size_t, size_t);
-    void updateCurrentRingBufferIfNeeded();
+    void clearRingBuffersIfPossible();
 
     std::atomic<bool> m_isStopped { false };
     bool m_writerIsStarted WTF_GUARDED_BY_CAPABILITY(queueSingleton()) { false };
@@ -152,9 +152,10 @@ class MediaRecorderPrivateEncoder final : public ThreadSafeRefCountedAndCanMakeT
     std::optional<AudioStreamBasicDescription> m_originalOutputDescription WTF_GUARDED_BY_CAPABILITY(queueSingleton());
     Deque<UniqueRef<MediaSamplesBlock>> m_encodedAudioFrames WTF_GUARDED_BY_CAPABILITY(queueSingleton());
     std::optional<std::pair<const MediaTime, GenericPromise::Producer>> m_pendingAudioFramePromise WTF_GUARDED_BY_CAPABILITY(queueSingleton());
-    Lock m_ringBuffersLock;
-    Deque<std::unique_ptr<InProcessCARingBuffer>> m_ringBuffers WTF_GUARDED_BY_LOCK(m_ringBuffersLock);
+    Deque<std::pair<std::unique_ptr<InProcessCARingBuffer>, size_t>, 4> m_ringBuffers;
+    size_t m_lastRingBufferId { 0 }; // accessed on the audio thread only.
     InProcessCARingBuffer* m_currentRingBuffer WTF_GUARDED_BY_CAPABILITY(queueSingleton()) { nullptr };
+    std::atomic<size_t> m_currentRingBufferId { 0 };
     std::atomic<int64_t> m_lastEnqueuedAudioTimeUs { 0 };
     std::atomic<int64_t> m_currentAudioTimeUs { 0 };
 


Reviews:
user: login: youennf
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T06:53:45Z
user: login: jyavenard
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-19T08:44:01Z

Review comments:
diff_hunk: @@ -350,42 +355,39 @@ void MediaRecorderPrivateEncoder::audioSamplesDescriptionChanged(const AudioStre
         return;
     }
 
-    updateCurrentRingBufferIfNeeded();
+    m_currentRingBuffer = newRingBuffer;
+    m_currentRingBufferId = ringBufferId;
 }
 
 void MediaRecorderPrivateEncoder::addRingBuffer(const AudioStreamDescription& description)
 {
     auto asbd = *std::get<const AudioStreamBasicDescription*>(description.platformDescription().description);
-    Locker locker { m_ringBuffersLock };
-    m_ringBuffers.append(InProcessCARingBuffer::allocate(asbd, description.sampleRate() * 2)); // allocate 2s of buffer.
-    queueSingleton().dispatch([weakThis = ThreadSafeWeakPtr { *this }, description = asbd] {
+    m_ringBuffers.append(std::make_pair(InProcessCARingBuffer::allocate(asbd, description.sampleRate() * 2), ++m_lastRingBufferId)); // allocate 2s of buffer.
+    queueSingleton().dispatch([weakThis = ThreadSafeWeakPtr { *this }, description = asbd, newRingBuffer = m_ringBuffers.last().first.get(), lastRingBufferId = m_lastRingBufferId] {
         if (RefPtr protectedThis = weakThis.get())
-            protectedThis->audioSamplesDescriptionChanged(description);
+            protectedThis->audioSamplesDescriptionChanged(description, newRingBuffer, lastRingBufferId);
     });
 }
 
 void MediaRecorderPrivateEncoder::writeDataToRingBuffer(AudioBufferList* list, size_t sampleCount, size_t totalSampleCount)
 {
-    Locker locker { m_ringBuffersLock };
-    if (m_ringBuffers.isEmpty() || !m_ringBuffers.last())
+    ASSERT(!m_ringBuffers.isEmpty());
+    if (!m_ringBuffers.last().first)
         return;
-    m_ringBuffers.last()->store(list, sampleCount, totalSampleCount);
+    m_ringBuffers.last().first->store(list, sampleCount, totalSampleCount);
 }
 
 void MediaRecorderPrivateEncoder::updateCurrentRingBufferIfNeeded()
path: Source/WebCore/platform/mediarecorder/MediaRecorderPrivateEncoder.cpp
user: login: youennf
body: It should be renamed to something like `clearRingBuffersIfPossible()`
created_at: 2025-05-19T06:50:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -350,42 +355,39 @@ void MediaRecorderPrivateEncoder::audioSamplesDescriptionChanged(const AudioStre
         return;
     }
 
-    updateCurrentRingBufferIfNeeded();
+    m_currentRingBuffer = newRingBuffer;
+    m_currentRingBufferId = ringBufferId;
 }
 
 void MediaRecorderPrivateEncoder::addRingBuffer(const AudioStreamDescription& description)
 {
     auto asbd = *std::get<const AudioStreamBasicDescription*>(description.platformDescription().description);
-    Locker locker { m_ringBuffersLock };
-    m_ringBuffers.append(InProcessCARingBuffer::allocate(asbd, description.sampleRate() * 2)); // allocate 2s of buffer.
-    queueSingleton().dispatch([weakThis = ThreadSafeWeakPtr { *this }, description = asbd] {
+    m_ringBuffers.append(std::make_pair(InProcessCARingBuffer::allocate(asbd, description.sampleRate() * 2), ++m_lastRingBufferId)); // allocate 2s of buffer.
+    queueSingleton().dispatch([weakThis = ThreadSafeWeakPtr { *this }, description = asbd, newRingBuffer = m_ringBuffers.last().first.get(), lastRingBufferId = m_lastRingBufferId] {
         if (RefPtr protectedThis = weakThis.get())
-            protectedThis->audioSamplesDescriptionChanged(description);
+            protectedThis->audioSamplesDescriptionChanged(description, newRingBuffer, lastRingBufferId);
     });
 }
 
 void MediaRecorderPrivateEncoder::writeDataToRingBuffer(AudioBufferList* list, size_t sampleCount, size_t totalSampleCount)
 {
-    Locker locker { m_ringBuffersLock };
-    if (m_ringBuffers.isEmpty() || !m_ringBuffers.last())
+    ASSERT(!m_ringBuffers.isEmpty());
+    if (!m_ringBuffers.last().first)
         return;
-    m_ringBuffers.last()->store(list, sampleCount, totalSampleCount);
+    m_ringBuffers.last().first->store(list, sampleCount, totalSampleCount);
 }
 
 void MediaRecorderPrivateEncoder::updateCurrentRingBufferIfNeeded()
 {
-    assertIsCurrent(queueSingleton());
-
-    Locker locker { m_ringBuffersLock };
-    if (m_currentRingBuffer) {
-        ASSERT(m_ringBuffers.size() > 1);
-        m_ringBuffers.removeFirst();
-    }
-    m_currentRingBuffer = m_ringBuffers.first().get();
-    if (!m_currentRingBuffer) {
-        RELEASE_LOG_ERROR(MediaStream, "MediaRecorderPrivateEncoder::audioSamplesDescriptionChanged: out of memory error occurred");
-        m_hadError = true;
-    }
+    if (m_ringBuffers.size() == 1)
+        return;
+    size_t currentRingBufferId = m_currentRingBufferId;
path: Source/WebCore/platform/mediarecorder/MediaRecorderPrivateEncoder.cpp
user: login: youennf
body: We might not even need this variable?
If so do, we need the if statement above?
created_at: 2025-05-19T06:51:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -350,42 +355,39 @@ void MediaRecorderPrivateEncoder::audioSamplesDescriptionChanged(const AudioStre
         return;
     }
 
-    updateCurrentRingBufferIfNeeded();
+    m_currentRingBuffer = newRingBuffer;
+    m_currentRingBufferId = ringBufferId;
 }
 
 void MediaRecorderPrivateEncoder::addRingBuffer(const AudioStreamDescription& description)
 {
     auto asbd = *std::get<const AudioStreamBasicDescription*>(description.platformDescription().description);
-    Locker locker { m_ringBuffersLock };
-    m_ringBuffers.append(InProcessCARingBuffer::allocate(asbd, description.sampleRate() * 2)); // allocate 2s of buffer.
-    queueSingleton().dispatch([weakThis = ThreadSafeWeakPtr { *this }, description = asbd] {
+    m_ringBuffers.append(std::make_pair(InProcessCARingBuffer::allocate(asbd, description.sampleRate() * 2), ++m_lastRingBufferId)); // allocate 2s of buffer.
+    queueSingleton().dispatch([weakThis = ThreadSafeWeakPtr { *this }, description = asbd, newRingBuffer = m_ringBuffers.last().first.get(), lastRingBufferId = m_lastRingBufferId] {
         if (RefPtr protectedThis = weakThis.get())
-            protectedThis->audioSamplesDescriptionChanged(description);
+            protectedThis->audioSamplesDescriptionChanged(description, newRingBuffer, lastRingBufferId);
     });
 }
 
 void MediaRecorderPrivateEncoder::writeDataToRingBuffer(AudioBufferList* list, size_t sampleCount, size_t totalSampleCount)
 {
-    Locker locker { m_ringBuffersLock };
-    if (m_ringBuffers.isEmpty() || !m_ringBuffers.last())
+    ASSERT(!m_ringBuffers.isEmpty());
+    if (!m_ringBuffers.last().first)
         return;
-    m_ringBuffers.last()->store(list, sampleCount, totalSampleCount);
+    m_ringBuffers.last().first->store(list, sampleCount, totalSampleCount);
 }
 
 void MediaRecorderPrivateEncoder::updateCurrentRingBufferIfNeeded()
 {
-    assertIsCurrent(queueSingleton());
-
-    Locker locker { m_ringBuffersLock };
-    if (m_currentRingBuffer) {
-        ASSERT(m_ringBuffers.size() > 1);
-        m_ringBuffers.removeFirst();
-    }
-    m_currentRingBuffer = m_ringBuffers.first().get();
-    if (!m_currentRingBuffer) {
-        RELEASE_LOG_ERROR(MediaStream, "MediaRecorderPrivateEncoder::audioSamplesDescriptionChanged: out of memory error occurred");
-        m_hadError = true;
-    }
+    if (m_ringBuffers.size() == 1)
+        return;
+    size_t currentRingBufferId = m_currentRingBufferId;
path: Source/WebCore/platform/mediarecorder/MediaRecorderPrivateEncoder.cpp
user: login: jyavenard
body: I didn't want to read the atomic multiple times unnecessarily.
And checking the size avoir reading the atomic if there's nothing pending
created_at: 2025-05-19T08:44:01Z
author_association: MEMBER

PR comments:
user: login: webkit-early-warning-system
created_at: 2025-05-17T11:32:25Z
body: EWS run on previous version of this PR (hash https://github.com/WebKit/WebKit/commit/bb888d22360a863935285f65b27f77d650303bef)<details>

| Misc | iOS, visionOS, tvOS & watchOS  | macOS  | Linux |  Windows |
| ----- | ---------------------- | ------- |  ----- |  --------- |
| [✅ 🧪 style](https://ews-build.webkit.org/#/builders/38/builds/103957 "Passed style check") | [✅ 🛠 ios](https://ews-build.webkit.org/#/builders/131/builds/23660 "Built successfully") | [✅ 🛠 mac](https://ews-build.webkit.org/#/builders/138/builds/13981 "Built successfully") | [✅ 🛠 wpe](https://ews-build.webkit.org/#/builders/5/builds/109150 "Built successfully") | [✅ 🛠 win](https://ews-build.webkit.org/#/builders/59/builds/54620 "Built successfully") 
| [✅ 🧪 bindings](https://ews-build.webkit.org/#/builders/9/builds/105997 "Passed tests") | [✅ 🛠 ios-sim](https://ews-build.webkit.org/#/builders/130/builds/24019 "Built successfully") | [✅ 🛠 mac-AS-debug](https://ews-build.webkit.org/#/builders/123/builds/32205 "Built successfully") | [  ~~🧪 wpe-wk2~~](https://ews-build.webkit.org/#/builders/34/builds/78968 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [⏳ 🧪 win-tests](https://ews-build.webkit.org/#/builders/Win-Tests-EWS "Waiting to run tests") 
| [✅ 🧪 webkitperl](https://ews-build.webkit.org/#/builders/11/builds/106963 "Passed tests") | [  ~~🧪 ios-wk2~~](https://ews-build.webkit.org/#/builders/132/builds/18654 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [✅ 🧪 api-mac](https://ews-build.webkit.org/#/builders/18/builds/93778 "Passed tests") | [✅ 🧪 api-wpe](https://ews-build.webkit.org/#/builders/41/builds/59296 "Passed tests") | 
| | [  ~~🧪 ios-wk2-wpt~~](https://ews-build.webkit.org/#/builders/133/builds/18443 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🧪 mac-wk1~~](https://ews-build.webkit.org/#/builders/135/builds/11829 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [✅ 🛠 wpe-cairo](https://ews-build.webkit.org/#/builders/65/builds/53985 "Built successfully") | 
| | [  ~~🧪 api-ios~~](https://ews-build.webkit.org/#/builders/13/builds/88187 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [✅ 🧪 mac-wk2](https://ews-build.webkit.org/#/builders/136/builds/11887 "Passed tests") | [✅ 🛠 gtk](https://ews-build.webkit.org/#/builders/2/builds/111537 "Built successfully") | 
| | [✅ 🛠 vision](https://ews-build.webkit.org/#/builders/128/builds/31113 "Built successfully") | [  ~~🧪 mac-AS-debug-wk2~~](https://ews-build.webkit.org/#/builders/122/builds/22926 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🧪 gtk-wk2~~](https://ews-build.webkit.org/#/builders/1/builds/87983 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | 
| | [✅ 🛠 vision-sim](https://ews-build.webkit.org/#/builders/121/builds/31477 "Built successfully") | [✅ 🧪 mac-wk2-stress](https://ews-build.webkit.org/#/builders/8/builds/89978 "Passed tests") | [  ~~🧪 api-gtk~~](https://ews-build.webkit.org/#/builders/21/builds/87639 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | 
| | [✅ 🧪 vision-wk2](https://ews-build.webkit.org/#/builders/126/builds/32524 "Passed tests") | [✅ 🧪 mac-intel-wk2](https://ews-build.webkit.org/#/builders/137/builds/10265 "Passed tests") | [  ~~🛠 playstation~~](https://ews-build.webkit.org/#/builders/134/builds/25493 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | 
| | [✅ 🛠 tv](https://ews-build.webkit.org/#/builders/127/builds/31042 "Built successfully") | [✅ 🛠 mac-safer-cpp](https://ews-build.webkit.org/#/builders/120/builds/36352 "Built successfully") | | 
| | [✅ 🛠 tv-sim](https://ews-build.webkit.org/#/builders/125/builds/30835 "Built successfully") | | | 
| | [✅ 🛠 watch](https://ews-build.webkit.org/#/builders/129/builds/34172 "Built successfully") | | | 
| | [✅ 🛠 watch-sim](https://ews-build.webkit.org/#/builders/124/builds/32396 "Built successfully") | | | </details>
author_association: COLLABORATOR
user: login: webkit-early-warning-system
created_at: 2025-05-17T11:37:24Z
body: EWS run on previous version of this PR (hash https://github.com/WebKit/WebKit/commit/6249ceaa90f9bccefbea31d5d504ec8de7a03484)<details>

| Misc | iOS, visionOS, tvOS & watchOS  | macOS  | Linux |  Windows |
| ----- | ---------------------- | ------- |  ----- |  --------- |
| [✅ 🧪 style](https://ews-build.webkit.org/#/builders/38/builds/103958 "Passed style check") | [✅ 🛠 ios](https://ews-build.webkit.org/#/builders/131/builds/23661 "Built successfully") | [✅ 🛠 mac](https://ews-build.webkit.org/#/builders/138/builds/13982 "Built successfully") | [✅ 🛠 wpe](https://ews-build.webkit.org/#/builders/5/builds/109151 "Built successfully") | [✅ 🛠 win](https://ews-build.webkit.org/#/builders/59/builds/54621 "Built successfully") 
| [✅ 🧪 bindings](https://ews-build.webkit.org/#/builders/9/builds/105998 "Passed tests") | [✅ 🛠 ios-sim](https://ews-build.webkit.org/#/builders/130/builds/24020 "Built successfully") | [✅ 🛠 mac-AS-debug](https://ews-build.webkit.org/#/builders/123/builds/32206 "Built successfully") | [✅ 🧪 wpe-wk2](https://ews-build.webkit.org/#/builders/34/builds/78970 "Passed tests") | [⏳ 🧪 win-tests](https://ews-build.webkit.org/#/builders/Win-Tests-EWS "Waiting to run tests") 
| [✅ 🧪 webkitperl](https://ews-build.webkit.org/#/builders/11/builds/106964 "Passed tests") | [✅ 🧪 ios-wk2](https://ews-build.webkit.org/#/builders/132/builds/18651 "Passed tests") | [✅ 🧪 api-mac](https://ews-build.webkit.org/#/builders/18/builds/93781 "Passed tests") | [✅ 🧪 api-wpe](https://ews-build.webkit.org/#/builders/41/builds/59298 "Passed tests") | 
| | [⏳ 🧪 ios-wk2-wpt](https://ews-build.webkit.org/#/builders/iOS-18-Simulator-WPT-WK2-Tests-EWS "Waiting to run tests") | [✅ 🧪 mac-wk1](https://ews-build.webkit.org/#/builders/135/builds/11832 "Passed tests") | [✅ 🛠 wpe-cairo](https://ews-build.webkit.org/#/builders/65/builds/53986 "Built successfully") | 
| | [⏳ 🧪 api-ios](https://ews-build.webkit.org/#/builders/API-Tests-iOS-Simulator-EWS "Waiting to run tests") | [✅ 🧪 mac-wk2](https://ews-build.webkit.org/#/builders/136/builds/11890 "Passed tests") | [✅ 🛠 gtk](https://ews-build.webkit.org/#/builders/2/builds/111538 "Built successfully") | 
| | [✅ 🛠 vision](https://ews-build.webkit.org/#/builders/128/builds/31114 "Built successfully") | [✅ 🧪 mac-AS-debug-wk2](https://ews-build.webkit.org/#/builders/122/builds/22925 "Passed tests") | [✅ 🧪 gtk-wk2](https://ews-build.webkit.org/#/builders/1/builds/87986 "Passed tests") | 
| | [✅ 🛠 vision-sim](https://ews-build.webkit.org/#/builders/121/builds/31478 "Built successfully") | [✅ 🧪 mac-wk2-stress](https://ews-build.webkit.org/#/builders/8/builds/89981 "Passed tests") | [✅ 🧪 api-gtk](https://ews-build.webkit.org/#/builders/21/builds/87642 "Passed tests") | 
| | [✅ 🧪 vision-wk2](https://ews-build.webkit.org/#/builders/126/builds/32525 "Passed tests") | [✅ 🧪 mac-intel-wk2](https://ews-build.webkit.org/#/builders/137/builds/10268 "Passed tests") | [✅ 🛠 playstation](https://ews-build.webkit.org/#/builders/134/builds/25489 "Built successfully") | 
| | [✅ 🛠 tv](https://ews-build.webkit.org/#/builders/127/builds/31043 "Built successfully") | [✅ 🛠 mac-safer-cpp](https://ews-build.webkit.org/#/builders/120/builds/36353 "Built successfully") | | 
| | [✅ 🛠 tv-sim](https://ews-build.webkit.org/#/builders/125/builds/30836 "Built successfully") | | | 
| | [✅ 🛠 watch](https://ews-build.webkit.org/#/builders/129/builds/34173 "Built successfully") | | | 
| | [✅ 🛠 watch-sim](https://ews-build.webkit.org/#/builders/124/builds/32397 "Built successfully") | | | </details>
author_association: COLLABORATOR
user: login: webkit-ews-buildbot
created_at: 2025-05-17T12:31:53Z
body: ### Safer C++ Build [#36353](https://ews-build.webkit.org/#/builders/120/builds/36353) (https://github.com/WebKit/WebKit/commit/6249ceaa90f9bccefbea31d5d504ec8de7a03484)

:warning: Found 1 fixed file! Please update expectations in `Source/[Project]/SaferCPPExpectations` by running the following command and update your pull request:
- `Tools/Scripts/update-safer-cpp-expectations -p WebCore --ForwardDeclChecker platform/mediarecorder/MediaRecorderPrivateEncoder.h`
author_association: COLLABORATOR
user: login: webkit-ews-buildbot
created_at: 2025-05-17T12:46:43Z
body: ### Safer C++ Build [#36352](https://ews-build.webkit.org/#/builders/120/builds/36352) (https://github.com/WebKit/WebKit/commit/bb888d22360a863935285f65b27f77d650303bef)

:warning: Found 1 fixed file! Please update expectations in `Source/[Project]/SaferCPPExpectations` by running the following command and update your pull request:
- `Tools/Scripts/update-safer-cpp-expectations -p WebCore --ForwardDeclChecker platform/mediarecorder/MediaRecorderPrivateEncoder.h`
author_association: COLLABORATOR
user: login: webkit-early-warning-system
created_at: 2025-05-19T08:55:29Z
body: EWS run on previous version of this PR (hash https://github.com/WebKit/WebKit/commit/2edd5061fb41614294d7689d580d5948117c9114)<details>

| Misc | iOS, visionOS, tvOS & watchOS  | macOS  | Linux |  Windows |
| ----- | ---------------------- | ------- |  ----- |  --------- |
| [✅ 🧪 style](https://ews-build.webkit.org/#/builders/38/builds/104078 "Passed style check") | [✅ 🛠 ios](https://ews-build.webkit.org/#/builders/131/builds/23782 "Built successfully") | [✅ 🛠 mac](https://ews-build.webkit.org/#/builders/138/builds/14102 "Built successfully") | [✅ 🛠 wpe](https://ews-build.webkit.org/#/builders/5/builds/109274 "Built successfully") | [✅ 🛠 win](https://ews-build.webkit.org/#/builders/59/builds/54746 "Built successfully") 
| [✅ 🧪 bindings](https://ews-build.webkit.org/#/builders/9/builds/106118 "Passed tests") | [✅ 🛠 ios-sim](https://ews-build.webkit.org/#/builders/130/builds/24149 "Built successfully") | [✅ 🛠 mac-AS-debug](https://ews-build.webkit.org/#/builders/123/builds/32326 "Built successfully") | [  ~~🧪 wpe-wk2~~](https://ews-build.webkit.org/#/builders/34/builds/79068 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [⏳ 🧪 win-tests](https://ews-build.webkit.org/#/builders/Win-Tests-EWS "Waiting to run tests") 
| [✅ 🧪 webkitperl](https://ews-build.webkit.org/#/builders/11/builds/107084 "Passed tests") | [✅ 🧪 ios-wk2](https://ews-build.webkit.org/#/builders/132/builds/18754 "Passed tests") | [  ~~🧪 api-mac~~](https://ews-build.webkit.org/#/builders/18/builds/93886 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🧪 api-wpe~~](https://ews-build.webkit.org/#/builders/41/builds/59395 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | 
| | [  ~~🧪 ios-wk2-wpt~~](https://ews-build.webkit.org/#/builders/133/builds/18556 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🧪 mac-wk1~~](https://ews-build.webkit.org/#/builders/135/builds/11932 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [✅ 🛠 wpe-cairo](https://ews-build.webkit.org/#/builders/65/builds/54106 "Built successfully") | 
| | [  ~~🧪 api-ios~~](https://ews-build.webkit.org/#/builders/13/builds/88277 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🧪 mac-wk2~~](https://ews-build.webkit.org/#/builders/136/builds/11990 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [✅ 🛠 gtk](https://ews-build.webkit.org/#/builders/2/builds/111660 "Built successfully") | 
| | [✅ 🛠 vision](https://ews-build.webkit.org/#/builders/128/builds/31234 "Built successfully") | [  ~~🧪 mac-AS-debug-wk2~~](https://ews-build.webkit.org/#/builders/122/builds/23024 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🧪 gtk-wk2~~](https://ews-build.webkit.org/#/builders/1/builds/88077 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | 
| | [✅ 🛠 vision-sim](https://ews-build.webkit.org/#/builders/121/builds/31598 "Built successfully") | [  ~~🧪 mac-wk2-stress~~](https://ews-build.webkit.org/#/builders/8/builds/90081 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🧪 api-gtk~~](https://ews-build.webkit.org/#/builders/21/builds/87734 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | 
| | [  ~~🧪 vision-wk2~~](https://ews-build.webkit.org/#/builders/126/builds/32619 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [⏳ 🧪 mac-intel-wk2](https://ews-build.webkit.org/#/builders/macOS-Sonoma-Release-WK2-Intel-Tests-EWS "Waiting to run tests") | [✅ 🛠 playstation](https://ews-build.webkit.org/#/builders/134/builds/25682 "Built successfully") | 
| | [✅ 🛠 tv](https://ews-build.webkit.org/#/builders/127/builds/31163 "Built successfully") | [✅ 🛠 mac-safer-cpp](https://ews-build.webkit.org/#/builders/120/builds/36475 "Built successfully") | | 
| | [  ~~🛠 tv-sim~~](https://ews-build.webkit.org/#/builders/125/builds/30957 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | | | 
| | [✅ 🛠 watch](https://ews-build.webkit.org/#/builders/129/builds/34293 "Built successfully") | | | 
| | [✅ 🛠 watch-sim](https://ews-build.webkit.org/#/builders/124/builds/32517 "Built successfully") | | | </details>
author_association: COLLABORATOR
user: login: webkit-early-warning-system
created_at: 2025-05-19T08:58:38Z
body: EWS run on current version of this PR (hash https://github.com/WebKit/WebKit/commit/bd80c39200fe122d1539bf8a721ff7893228b68b)<details>

| Misc | iOS, visionOS, tvOS & watchOS  | macOS  | Linux |  Windows |
| ----- | ---------------------- | ------- |  ----- |  --------- |
| [✅ 🧪 style](https://ews-build.webkit.org/#/builders/38/builds/104079 "Passed style check") | [✅ 🛠 ios](https://ews-build.webkit.org/#/builders/131/builds/23783 "Built successfully") | [✅ 🛠 mac](https://ews-build.webkit.org/#/builders/138/builds/14103 "Built successfully") | [✅ 🛠 wpe](https://ews-build.webkit.org/#/builders/5/builds/109275 "Built successfully") | [✅ 🛠 win](https://ews-build.webkit.org/#/builders/59/builds/54747 "Built successfully") 
| [✅ 🧪 bindings](https://ews-build.webkit.org/#/builders/9/builds/106119 "Passed tests") | [✅ 🛠 ios-sim](https://ews-build.webkit.org/#/builders/130/builds/24150 "Built successfully") | [✅ 🛠 mac-AS-debug](https://ews-build.webkit.org/#/builders/123/builds/32327 "Built successfully") | [✅ 🧪 wpe-wk2](https://ews-build.webkit.org/#/builders/34/builds/79067 "Passed tests") | [⏳ 🧪 win-tests](https://ews-build.webkit.org/#/builders/Win-Tests-EWS "Waiting to run tests") 
| [✅ 🧪 webkitperl](https://ews-build.webkit.org/#/builders/11/builds/107085 "Passed tests") | [✅ 🧪 ios-wk2](https://ews-build.webkit.org/#/builders/132/builds/18756 "Passed tests") | [✅ 🧪 api-mac](https://ews-build.webkit.org/#/builders/18/builds/93887 "Passed tests") | [❌ 🧪 api-wpe](https://ews-build.webkit.org/#/builders/41/builds/59394 "Found 1 new API test failure: /WPE/TestCookieManager:/webkit/WebKitCookieManager/persistent-storage (failure)") | 
| | [✅ 🧪 ios-wk2-wpt](https://ews-build.webkit.org/#/builders/133/builds/18562 "Passed tests") | [✅ 🧪 mac-wk1](https://ews-build.webkit.org/#/builders/135/builds/11933 "Passed tests") | [✅ 🛠 wpe-cairo](https://ews-build.webkit.org/#/builders/65/builds/54107 "Built successfully") | 
| | [✅ 🧪 api-ios](https://ews-build.webkit.org/#/builders/13/builds/88279 "Passed tests") | [✅ 🧪 mac-wk2](https://ews-build.webkit.org/#/builders/136/builds/11991 "Passed tests") | [✅ 🛠 gtk](https://ews-build.webkit.org/#/builders/2/builds/111661 "Built successfully") | 
| | [✅ 🛠 vision](https://ews-build.webkit.org/#/builders/128/builds/31235 "Built successfully") | [✅ 🧪 mac-AS-debug-wk2](https://ews-build.webkit.org/#/builders/122/builds/23028 "Passed tests") | [✅ 🧪 gtk-wk2](https://ews-build.webkit.org/#/builders/1/builds/88078 "Passed tests") | 
| | [✅ 🛠 vision-sim](https://ews-build.webkit.org/#/builders/121/builds/31599 "Built successfully") | [✅ 🧪 mac-wk2-stress](https://ews-build.webkit.org/#/builders/8/builds/90082 "Passed tests") | [❌ 🧪 api-gtk](https://ews-build.webkit.org/#/builders/21/builds/87735 "Found 99 new API test failures: /WebKitGTK/TestInputMethodContext:/webkit/WebKitInputMethodContext/invalid-sequence, /WebKitGTK/TestDownloads:/webkit/Downloads/blob-download, /WebKitGTK/TestUIClient:/webkit/WebKitWebView/mouse-target, /TestWebKit:WebKit.UserMediaBasic, /WebKitGTK/TestWebProcessExtensions:/webkit/WebKitWebProcessExtension/dom-input-element-is-user-edited, /WebKitGTK/TestDownloads:/webkit/Downloads/contex-menu-download-actions, /WebKitGTK/TestInputMethodContext:/webkit/WebKitInputMethodContext/cancel-sequence, /WebKitGTK/TestWebKitWebView:/webkit/WebKitWebView/is-playing-audio, /WebKitGTK/TestWebKitWebView:/webkit/WebKitWebView/page-visibility, /WebKitGTK/TestOptionMenu:/webkit/WebKitWebView/option-menu-select ... (failure)") | 
| [✅ 🛠 🧪 merge](https://ews-build.webkit.org/#/builders/19/builds/22329 "Built successfully and passed tests") | [✅ 🧪 vision-wk2](https://ews-build.webkit.org/#/builders/126/builds/32615 "Passed tests") | [✅ 🧪 mac-intel-wk2](https://ews-build.webkit.org/#/builders/137/builds/10368 "Passed tests") | [✅ 🛠 playstation](https://ews-build.webkit.org/#/builders/134/builds/25683 "Built successfully") | 
| | [✅ 🛠 tv](https://ews-build.webkit.org/#/builders/127/builds/31164 "Built successfully") | [✅ 🛠 mac-safer-cpp](https://ews-build.webkit.org/#/builders/120/builds/36476 "Built successfully") | | 
| | [✅ 🛠 tv-sim](https://ews-build.webkit.org/#/builders/125/builds/30958 "Built successfully") | | | 
| | [✅ 🛠 watch](https://ews-build.webkit.org/#/builders/129/builds/34294 "Built successfully") | | | 
| | [✅ 🛠 watch-sim](https://ews-build.webkit.org/#/builders/124/builds/32518 "Built successfully") | | | </details>
author_association: COLLABORATOR
user: login: webkit-ews-buildbot
created_at: 2025-05-19T09:51:29Z
body: ### Safer C++ Build [#36475](https://ews-build.webkit.org/#/builders/120/builds/36475) (https://github.com/WebKit/WebKit/commit/2edd5061fb41614294d7689d580d5948117c9114)

:warning: Found 1 fixed file! Please update expectations in `Source/[Project]/SaferCPPExpectations` by running the following command and update your pull request:
- `Tools/Scripts/update-safer-cpp-expectations -p WebCore --ForwardDeclChecker platform/mediarecorder/MediaRecorderPrivateEncoder.h`
author_association: COLLABORATOR
user: login: webkit-commit-queue
created_at: 2025-05-19T11:08:35Z
body: Committed 295090@main (61d17594f7e3): <https://commits.webkit.org/295090@main>

Reviewed commits have been landed. Closing PR #45544 and removing active labels.
author_association: COLLABORATOR