Skip to content

Commit d8fe367

Browse files
committed
Bug 1993981 - Unit test message atomicity. r=karlt
Differential Revision: https://phabricator.services.mozilla.com/D277180
1 parent 534803c commit d8fe367

1 file changed

Lines changed: 114 additions & 1 deletion

File tree

‎dom/media/gtest/TestAudioTrackGraph.cpp‎

Lines changed: 114 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "DeviceInputTrack.h"
77
#include "MediaTrackGraphImpl.h"
88
#include "StaticComponents.h"
9+
#include "VideoUtils.h"
910
#include "gmock/gmock.h"
1011
#include "gtest/gtest-printers.h"
1112
#include "gtest/gtest.h"
@@ -3642,7 +3643,6 @@ TEST(TestAudioTrackGraph, MessageOrdering)
36423643
InSequence s;
36433644
EXPECT_CALL(checkpoint, Call(StrEq("Prior to tail dispatch")));
36443645
EXPECT_CALL(*processedTrack, AddListenerImpl);
3645-
EXPECT_CALL(*processedTrack, ProcessInput).Times(AtLeast(0));
36463646
EXPECT_CALL(checkpoint, Call(StrEq("1-main->graph")));
36473647
EXPECT_CALL(*processedTrack, ProcessInput).Times(AtLeast(1));
36483648
EXPECT_CALL(checkpoint, Call(StrEq("processed task on main")))
@@ -3861,6 +3861,119 @@ TEST(TestAudioTrackGraph, MessageOrdering)
38613861
(void)WaitFor(destroyPromise).unwrap()[0];
38623862
}
38633863

3864+
TEST(TestAudioTrackGraph, MessageAtomicity)
3865+
{
3866+
MockCubeb* cubeb = new MockCubeb(MockCubeb::RunningMode::Manual);
3867+
CubebUtils::ForceSetCubebContext(cubeb->AsCubebContext());
3868+
3869+
MediaTrackGraphImpl* graph = MediaTrackGraphImpl::GetInstance(
3870+
MediaTrackGraph::SYSTEM_THREAD_DRIVER, /*Window ID*/ 1,
3871+
CubebUtils::PreferredSampleRate(/* aShouldResistFingerprinting */ false),
3872+
nullptr, AbstractThread::MainThread());
3873+
3874+
// Mocks and expectations.
3875+
RefPtr processedTrack = new MockProcessedMediaTrack(graph->GraphRate());
3876+
3877+
MockFunction<void(const char* name)> checkpoint;
3878+
{
3879+
InSequence s;
3880+
EXPECT_CALL(*processedTrack, AddListenerImpl);
3881+
EXPECT_CALL(*processedTrack, ProcessInput).Times(AtLeast(0));
3882+
// All "Main" graph tasks dispatch in one group and run atomically.
3883+
EXPECT_CALL(checkpoint, Call(StrEq("Main"))).Times(500);
3884+
// All "Other" tq tasks dispatch in one group, then dispatch in one group to
3885+
// the graph, and run atomically.
3886+
EXPECT_CALL(checkpoint, Call(StrEq("Other"))).Times(500);
3887+
EXPECT_CALL(*processedTrack, ProcessInput);
3888+
EXPECT_CALL(*processedTrack, RemoveListenerImpl);
3889+
}
3890+
3891+
// Add a track to maintain an output-only audio driver.
3892+
RefPtr<OnFallbackListener> fallbackListener;
3893+
DispatchFunction([&] {
3894+
graph->AddTrack(processedTrack);
3895+
processedTrack->AddAudioOutput(reinterpret_cast<void*>(1), nullptr);
3896+
fallbackListener = new OnFallbackListener(processedTrack);
3897+
processedTrack->AddListener(fallbackListener);
3898+
});
3899+
3900+
RefPtr<SmartMockCubebStream> stream = WaitFor(cubeb->StreamInitEvent());
3901+
while (stream->State().isNothing()) {
3902+
std::this_thread::sleep_for(std::chrono::milliseconds(1));
3903+
}
3904+
EXPECT_EQ(*stream->State(), CUBEB_STATE_STARTED);
3905+
// Wait for the AudioCallbackDriver to come into effect.
3906+
DispatchFunction([&] {
3907+
while (fallbackListener->OnFallback()) {
3908+
EXPECT_EQ(stream->ManualDataCallback(WEBAUDIO_BLOCK_SIZE),
3909+
MockCubebStream::KeepProcessing::Yes);
3910+
std::this_thread::sleep_for(std::chrono::milliseconds(1));
3911+
}
3912+
});
3913+
3914+
// The graph is now run by ManualDataCallback().
3915+
3916+
// Run the setup tasks in the graph. They run prior to processing tracks.
3917+
DispatchFunction([&] {
3918+
EXPECT_EQ(stream->ManualDataCallback(2 * WEBAUDIO_BLOCK_SIZE),
3919+
MockCubebStream::KeepProcessing::Yes);
3920+
});
3921+
3922+
auto tq =
3923+
TaskQueue::Create(GetMediaThreadPool(MediaThreadType::WEBRTC_WORKER),
3924+
__func__, /*aSupportsTailDispatch=*/true);
3925+
3926+
// Dispatch task A to the graph, then task B to another tail-dispatchable
3927+
// target, then task C to the graph again. Tail dispatch preserves target
3928+
// dispatch ordering by default, guaranteeing that a task dispatched from B to
3929+
// the graph cannot run before A.
3930+
// The graph requires task atomicity however, meaning that A and C must run in
3931+
// the same graph iteration.
3932+
// This is hard to test because the graph drains all direct tasks at the end
3933+
// of the iteration, rather than in between tasks. Do *many* dispatches and
3934+
// rely on racing with the other target dispatching to the graph, instead.
3935+
DispatchFunction([&] {
3936+
for (size_t i = 0; i < 500; ++i) {
3937+
EXPECT_TRUE(NS_SUCCEEDED(graph->Dispatch(
3938+
NS_NewRunnableFunction(__func__, [&] { checkpoint.Call("Main"); }))));
3939+
EXPECT_TRUE(
3940+
NS_SUCCEEDED(tq->Dispatch(NS_NewRunnableFunction(__func__, [&] {
3941+
EXPECT_TRUE(NS_SUCCEEDED(graph->Dispatch(NS_NewRunnableFunction(
3942+
"TaskQueue.Task", [&] { checkpoint.Call("Other"); }))));
3943+
}))));
3944+
}
3945+
});
3946+
3947+
// Run the dispatched functions with tail dispatch after each.
3948+
ProcessEventQueue();
3949+
3950+
// Wait for tq to do all its dispatches.
3951+
WaitForMirrors(tq);
3952+
3953+
// Run graph runnables, at beginning of iteration.
3954+
DispatchFunction([&] {
3955+
EXPECT_EQ(stream->ManualDataCallback(WEBAUDIO_BLOCK_SIZE),
3956+
MockCubebStream::KeepProcessing::Yes);
3957+
});
3958+
3959+
DispatchFunction([&] {
3960+
processedTrack->RemoveListener(fallbackListener);
3961+
processedTrack->Destroy();
3962+
});
3963+
3964+
// Process the destroy message and drain the stream.
3965+
auto destroyPromise = TakeN(cubeb->StreamDestroyEvent(), 1);
3966+
DispatchFunction([&] {
3967+
while (stream->ManualDataCallback(0) ==
3968+
MockCubebStream::KeepProcessing::Yes) {
3969+
}
3970+
});
3971+
// Ensure the stream is no longer used by its MockCubeb before releasing our
3972+
// reference, and before the next test might ForceSetCubebContext() to
3973+
// destroy our cubeb.
3974+
(void)WaitFor(destroyPromise).unwrap()[0];
3975+
}
3976+
38643977
#undef InvokeAsync
38653978
#undef TEST_WithTailDispatch
38663979
#undef DispatchFunction

0 commit comments

Comments
 (0)