Allow constructing objects on one thread and use on another.
Allow AudioState and AudioDeviceBuffer to be constructed on one thread
but used and destroyed on another.
This is a prerequisite for allowing asynchronous termination of the
WebRtcVoiceEngine.
Bug: webrtc:42224720
Change-Id: I586f2ef84cd34137eee2d57b9d954f3ed45a8898
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/410862
Commit-Queue: Tomas Gunnarsson <tommi@webrtc.org>
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#45697}
diff --git a/audio/BUILD.gn b/audio/BUILD.gn
index 3773ab8..3776dac 100644
--- a/audio/BUILD.gn
+++ b/audio/BUILD.gn
@@ -186,6 +186,7 @@
"../api:mock_frame_encryptor",
"../api:mock_frame_transformer",
"../api:mock_transformable_audio_frame",
+ "../api:ref_count",
"../api:rtc_error_matchers",
"../api:rtp_headers",
"../api:rtp_parameters",
diff --git a/audio/audio_state.h b/audio/audio_state.h
index 6a2d236..bfac44f 100644
--- a/audio/audio_state.h
+++ b/audio/audio_state.h
@@ -21,6 +21,7 @@
#include "call/audio_state.h"
#include "rtc_base/checks.h"
#include "rtc_base/containers/flat_set.h"
+#include "rtc_base/system/no_unique_address.h"
#include "rtc_base/task_utils/repeating_task.h"
#include "rtc_base/thread_annotations.h"
@@ -66,8 +67,10 @@
void UpdateAudioTransportWithSendingStreams();
void UpdateNullAudioPollerState() RTC_RUN_ON(&thread_checker_);
- SequenceChecker thread_checker_;
- SequenceChecker process_thread_checker_{SequenceChecker::kDetached};
+ RTC_NO_UNIQUE_ADDRESS SequenceChecker thread_checker_{
+ SequenceChecker::kDetached};
+ RTC_NO_UNIQUE_ADDRESS SequenceChecker process_thread_checker_{
+ SequenceChecker::kDetached};
const webrtc::AudioState::Config config_;
bool recording_enabled_ = true;
bool playout_enabled_ = true;
diff --git a/audio/audio_state_unittest.cc b/audio/audio_state_unittest.cc
index 534cb11..c331210 100644
--- a/audio/audio_state_unittest.cc
+++ b/audio/audio_state_unittest.cc
@@ -26,6 +26,7 @@
#include "api/audio/audio_mixer.h"
#include "api/location.h"
#include "api/make_ref_counted.h"
+#include "api/ref_count.h"
#include "api/scoped_refptr.h"
#include "api/task_queue/task_queue_base.h"
#include "api/task_queue/task_queue_factory.h"
@@ -37,6 +38,7 @@
#include "modules/audio_device/include/mock_audio_device.h"
#include "modules/audio_mixer/audio_mixer_impl.h"
#include "modules/audio_processing/include/mock_audio_processing.h"
+#include "rtc_base/task_queue_for_test.h"
#include "rtc_base/thread.h"
#include "test/gmock.h"
#include "test/gtest.h"
@@ -49,6 +51,7 @@
using ::testing::InSequence;
using ::testing::Matcher;
using ::testing::NiceMock;
+using ::testing::NotNull;
using ::testing::StrictMock;
using ::testing::Values;
@@ -200,6 +203,20 @@
make_ref_counted<internal::AudioState>(helper.config()));
}
+TEST_P(AudioStateTest, CreateUseDeleteOnDifferentThread) {
+ ConfigHelper helper(GetParam());
+ scoped_refptr<AudioState> audio_state = AudioState::Create(helper.config());
+ ASSERT_THAT(audio_state, NotNull());
+ TaskQueueForTest queue;
+ queue.SendTask([&] {
+ // Attach to the current TQ.
+ audio_state->SetStereoChannelSwapping(true);
+ // Ensure the object gets deleted on the current thread.
+ EXPECT_EQ(audio_state.release()->Release(),
+ RefCountReleaseStatus::kDroppedLastRef);
+ });
+}
+
TEST_P(AudioStateTest, RecordedAudioArrivesAtSingleStream) {
ConfigHelper helper(GetParam());
diff --git a/modules/audio_device/BUILD.gn b/modules/audio_device/BUILD.gn
index 8e8a4bf..c8b15e4 100644
--- a/modules/audio_device/BUILD.gn
+++ b/modules/audio_device/BUILD.gn
@@ -74,6 +74,7 @@
"../../rtc_base:timestamp_aligner",
"../../rtc_base:timeutils",
"../../rtc_base/synchronization:mutex",
+ "../../rtc_base/system:no_unique_address",
"../../system_wrappers",
"../../system_wrappers:metrics",
]
@@ -478,6 +479,7 @@
"../../rtc_base:race_checker",
"../../rtc_base:rtc_event",
"../../rtc_base:safe_conversions",
+ "../../rtc_base:task_queue_for_test",
"../../rtc_base:timeutils",
"../../rtc_base/synchronization:mutex",
"../../system_wrappers",
diff --git a/modules/audio_device/audio_device_buffer.h b/modules/audio_device/audio_device_buffer.h
index d518081..838ca80 100644
--- a/modules/audio_device/audio_device_buffer.h
+++ b/modules/audio_device/audio_device_buffer.h
@@ -23,6 +23,7 @@
#include "api/task_queue/task_queue_base.h"
#include "rtc_base/buffer.h"
#include "rtc_base/synchronization/mutex.h"
+#include "rtc_base/system/no_unique_address.h"
#include "rtc_base/thread_annotations.h"
#include "rtc_base/timestamp_aligner.h"
@@ -153,8 +154,9 @@
// edge cases and it is IMHO not worth the risk to use them in this class.
// TODO(henrika): see if it is possible to refactor and annotate all members.
- // Main thread on which this object is created.
- SequenceChecker main_thread_checker_;
+ // Main thread for where this object is used.
+ RTC_NO_UNIQUE_ADDRESS SequenceChecker main_thread_checker_{
+ SequenceChecker::kDetached};
Mutex lock_;
diff --git a/modules/audio_device/test_audio_device_impl_test.cc b/modules/audio_device/test_audio_device_impl_test.cc
index cab3ed7..4c0644d 100644
--- a/modules/audio_device/test_audio_device_impl_test.cc
+++ b/modules/audio_device/test_audio_device_impl_test.cc
@@ -26,6 +26,7 @@
#include "modules/audio_device/include/test_audio_device.h"
#include "rtc_base/checks.h"
#include "rtc_base/synchronization/mutex.h"
+#include "rtc_base/task_queue_for_test.h"
#include "rtc_base/thread_annotations.h"
#include "test/create_test_environment.h"
#include "test/gmock.h"
@@ -187,6 +188,20 @@
ElementsAre(48000, 48000, 48000));
}
+// Construct an AudioDeviceBuffer on one thread, use it and delete it on a
+// different thread.
+TEST(TestAudioDeviceTest, AudioDeviceBufferOnDifferentThread) {
+ GlobalSimulatedTimeController time_controller(kStartTime);
+ const Environment env = CreateTestEnvironment({.time = &time_controller});
+ auto audio_buffer = std::make_unique<AudioDeviceBuffer>(env);
+ TaskQueueForTest queue;
+ queue.SendTask([&] {
+ TestAudioTransport audio_transport(TestAudioTransport::Mode::kRecording);
+ ASSERT_EQ(audio_buffer->RegisterAudioCallback(&audio_transport), 0);
+ audio_buffer = nullptr;
+ });
+}
+
TEST(TestAudioDeviceTest, RecordingIsAvailableWhenCapturerIsSet) {
GlobalSimulatedTimeController time_controller(kStartTime);
std::unique_ptr<TestAudioDeviceModule::PulsedNoiseCapturer> capturer =