commit 9b0b961626615d8c1c7a1ceae376bd8e18bcfff8
parent 70425199e9a5fa80aa7419fa51763013a67226e1
Author: Karl Tomlinson <karlt+@karlt.net>
Date: Wed, 19 Nov 2025 21:53:10 +0000
Bug 2000076 Take graph control messages from main thread before processing control messages r=pehrsons
Messages are no longer held for a whole iteration interval before processing.
SwapElements() no longer needs to EnsureNextIteration() because
mFrontMessageQueue is now processed in the same iteration as the swap.
Differential Revision: https://phabricator.services.mozilla.com/D272607
Diffstat:
3 files changed, 14 insertions(+), 48 deletions(-)
diff --git a/dom/media/MediaTrackGraph.cpp b/dom/media/MediaTrackGraph.cpp
@@ -1613,7 +1613,6 @@ bool MediaTrackGraphImpl::UpdateMainThreadState() {
mForceShutDownReceived || (IsEmpty() && mBackMessageQueue.IsEmpty());
PrepareUpdatesToMainThreadState(finalUpdate);
if (!finalUpdate) {
- SwapMessageQueues();
return true;
}
// The JSContext will not be used again.
@@ -1668,6 +1667,7 @@ auto MediaTrackGraphImpl::OneIterationImpl(
WebCore::DenormalDisabler disabler;
// Process graph message from the main thread for this iteration.
+ SwapMessageQueues();
RunMessagesInQueue();
// Process MessagePort events.
@@ -2075,10 +2075,8 @@ void MediaTrackGraphImpl::RunInStableState(bool aSourceIsMTG) {
if (LifecycleStateRef() == LIFECYCLE_THREAD_NOT_STARTED) {
// Start the driver now. We couldn't start it earlier because the graph
// might exit immediately on finding it has no tracks. The first message
- // for a new graph must create a track. Ensure that his message runs on
- // the first iteration.
+ // for a new graph must create a track.
MOZ_ASSERT(MessagesQueued());
- SwapMessageQueues();
LOG(LogLevel::Debug,
("%p: Starting a graph with a %s", this,
diff --git a/dom/media/MediaTrackGraphImpl.h b/dom/media/MediaTrackGraphImpl.h
@@ -355,14 +355,11 @@ class MediaTrackGraphImpl : public MediaTrackGraph,
*/
void UpdateGraph(GraphTime aEndBlockingDecisions);
- void SwapMessageQueues() MOZ_REQUIRES(mMonitor) {
+ void SwapMessageQueues() {
+ MonitorAutoLock lock(mMonitor);
MOZ_ASSERT(OnGraphThreadOrNotRunning());
- mMonitor.AssertCurrentThreadOwns();
MOZ_ASSERT(mFrontMessageQueue.IsEmpty());
mFrontMessageQueue.SwapElements(mBackMessageQueue);
- if (!mFrontMessageQueue.IsEmpty()) {
- EnsureNextIteration();
- }
}
/**
* Do all the processing and play the audio and video, from
diff --git a/dom/media/gtest/TestAudioTrackGraph.cpp b/dom/media/gtest/TestAudioTrackGraph.cpp
@@ -1376,10 +1376,7 @@ TEST(TestAudioTrackGraph, ReConnectDeviceInput)
// Dispatch the disconnect message.
ProcessEventQueue();
- // Run the disconnect message.
- EXPECT_EQ(stream->ManualDataCallback(0),
- MockCubebStream::KeepProcessing::Yes);
- // Switch driver.
+ // Run the disconnect message and switch driver.
auto initPromise = TakeN(cubeb->StreamInitEvent(), 1);
EXPECT_EQ(stream->ManualDataCallback(0), MockCubebStream::KeepProcessing::No);
std::tie(stream) = WaitFor(initPromise).unwrap()[0];
@@ -1413,10 +1410,7 @@ TEST(TestAudioTrackGraph, ReConnectDeviceInput)
});
// Dispatch the connect message.
ProcessEventQueue();
- // Run the connect message.
- EXPECT_EQ(stream->ManualDataCallback(0),
- MockCubebStream::KeepProcessing::Yes);
- // Switch driver.
+ // Run the connect message and switch driver.
initPromise = TakeN(cubeb->StreamInitEvent(), 1);
EXPECT_EQ(stream->ManualDataCallback(0), MockCubebStream::KeepProcessing::No);
std::tie(stream) = WaitFor(initPromise).unwrap()[0];
@@ -1456,10 +1450,7 @@ TEST(TestAudioTrackGraph, ReConnectDeviceInput)
// Dispatch the clean-up messages.
ProcessEventQueue();
- // Run the clean-up messages.
- EXPECT_EQ(stream->ManualDataCallback(0),
- MockCubebStream::KeepProcessing::Yes);
- // Shut down driver.
+ // Run the clean-up messages and shut down driver.
EXPECT_EQ(stream->ManualDataCallback(0), MockCubebStream::KeepProcessing::No);
uint32_t inputFrequency = stream->InputFrequency();
@@ -2517,11 +2508,6 @@ void TestCrossGraphPort(uint32_t aInputRate, uint32_t aOutputRate,
ProcessEventQueue();
- EXPECT_EQ(inputStream->ManualDataCallback(0),
- MockCubebStream::KeepProcessing::Yes);
- EXPECT_EQ(partnerStream->ManualDataCallback(0),
- MockCubebStream::KeepProcessing::Yes);
-
EXPECT_EQ(inputStream->ManualDataCallback(128),
MockCubebStream::KeepProcessing::No);
EXPECT_EQ(partnerStream->ManualDataCallback(128),
@@ -2979,10 +2965,7 @@ TEST(TestAudioTrackGraph, PlatformProcessing)
[&] { graph->ReevaluateInputDevice(device); });
});
ProcessEventQueue();
- // Process the reevaluation message.
- EXPECT_EQ(stream->ManualDataCallback(0),
- MockCubebStream::KeepProcessing::Yes);
- // Perform the switch.
+ // Process the reevaluation message and perform the switch.
auto initPromise = TakeN(cubeb->StreamInitEvent(), 1);
EXPECT_EQ(stream->ManualDataCallback(0), MockCubebStream::KeepProcessing::No);
std::tie(stream) = WaitFor(initPromise).unwrap()[0];
@@ -3032,10 +3015,7 @@ TEST(TestAudioTrackGraph, PlatformProcessing)
track->Destroy();
});
ProcessEventQueue();
- // Process the destroy message.
- EXPECT_EQ(stream->ManualDataCallback(0),
- MockCubebStream::KeepProcessing::Yes);
- // Shut down.
+ // Process the destroy message and shut down.
EXPECT_EQ(stream->ManualDataCallback(0), MockCubebStream::KeepProcessing::No);
RefPtr<SmartMockCubebStream> destroyedStream =
WaitFor(cubeb->StreamDestroyEvent());
@@ -3246,11 +3226,8 @@ TEST(TestAudioTrackGraph, PlatformProcessingNonNativeToNativeSwitch)
});
ProcessEventQueue();
initPromise = TakeN(cubeb->StreamInitEvent(), 1);
- // Process the disconnect message, and check that the second device is now
- // used with the new graph driver.
- EXPECT_EQ(nativeStream->ManualDataCallback(0),
- MockCubebStream::KeepProcessing::Yes);
- // Perform the switch.
+ // Process the disconnect message, perform the switch,
+ // and check that the second device is now used with the new graph driver.
EXPECT_EQ(nativeStream->ManualDataCallback(0),
MockCubebStream::KeepProcessing::No);
std::tie(nativeStream) = WaitFor(initPromise).unwrap()[0];
@@ -3294,10 +3271,7 @@ TEST(TestAudioTrackGraph, PlatformProcessingNonNativeToNativeSwitch)
auto destroyPromise = TakeN(cubeb->StreamDestroyEvent(), 1);
DispatchFunction([&] {
ProcessEventQueue();
- // Process the destroy message.
- EXPECT_EQ(nativeStream->ManualDataCallback(0),
- MockCubebStream::KeepProcessing::Yes);
- // Shut down native.
+ // Process the destroy message and shut down native.
EXPECT_EQ(nativeStream->ManualDataCallback(0),
MockCubebStream::KeepProcessing::No);
});
@@ -3470,11 +3444,8 @@ TEST(TestAudioTrackGraph, DefaultOutputDeviceIDTracking)
});
auto initPromise = TakeN(cubeb->StreamInitEvent(), 1);
ProcessEventQueue();
- // Process the disconnect message, and check that the second device is now
- // used with the new graph driver.
- EXPECT_EQ(stream->ManualDataCallback(0),
- MockCubebStream::KeepProcessing::Yes);
- // Perform the switch.
+ // Process the disconnect message, perform the switch,
+ // and check that the second device is now used with the new graph driver.
EXPECT_EQ(stream->ManualDataCallback(0), MockCubebStream::KeepProcessing::No);
std::tie(stream) = WaitFor(initPromise).unwrap()[0];
EXPECT_TRUE(stream->mHasInput);