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 =