Remove rtc::TaskQueue in AudioDeviceBuffer

Instead stop/delete TaskQueueBase in destructor explicitly and explain potential race.

Bug: webrtc:14169
Change-Id: Ica7a78f149be11ba1a82cbf79d4244c918aa9d0a
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/335360
Reviewed-by: Tomas Gunnarsson <tommi@webrtc.org>
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#41810}
diff --git a/modules/audio_device/BUILD.gn b/modules/audio_device/BUILD.gn
index 2088e74..e5f8463 100644
--- a/modules/audio_device/BUILD.gn
+++ b/modules/audio_device/BUILD.gn
@@ -80,7 +80,6 @@
     "../../rtc_base:event_tracer",
     "../../rtc_base:logging",
     "../../rtc_base:macromagic",
-    "../../rtc_base:rtc_task_queue",
     "../../rtc_base:safe_conversions",
     "../../rtc_base:timestamp_aligner",
     "../../rtc_base:timeutils",
diff --git a/modules/audio_device/audio_device_buffer.cc b/modules/audio_device/audio_device_buffer.cc
index f1bd8e8..38ed633 100644
--- a/modules/audio_device/audio_device_buffer.cc
+++ b/modules/audio_device/audio_device_buffer.cc
@@ -78,6 +78,17 @@
   RTC_DCHECK(!playing_);
   RTC_DCHECK(!recording_);
   RTC_LOG(LS_INFO) << "AudioDeviceBuffer::~dtor";
+
+  // Delete and and thus stop task queue before deleting other members to avoid
+  // race with running tasks. Even though !playing_ and !recording_ called
+  // StopPeriodicLogging, such stop is asynchronous and may race with the
+  // AudioDeviceBuffer destructor. In particular there might be regular LogStats
+  // that attempts to repost task to the task_queue_.
+  // Thus task_queue_ should be deleted before pointer to it is invalidated.
+  // std::unique_ptr destructor does the same two operations in reverse order as
+  // it doesn't expect member would be used after its destruction has started.
+  task_queue_.get_deleter()(task_queue_.get());
+  task_queue_.release();
 }
 
 int32_t AudioDeviceBuffer::RegisterAudioCallback(
@@ -102,7 +113,7 @@
   }
   RTC_DLOG(LS_INFO) << __FUNCTION__;
   // Clear members tracking playout stats and do it on the task queue.
-  task_queue_.PostTask([this] { ResetPlayStats(); });
+  task_queue_->PostTask([this] { ResetPlayStats(); });
   // Start a periodic timer based on task queue if not already done by the
   // recording side.
   if (!recording_) {
@@ -121,7 +132,7 @@
   }
   RTC_DLOG(LS_INFO) << __FUNCTION__;
   // Clear members tracking recording stats and do it on the task queue.
-  task_queue_.PostTask([this] { ResetRecStats(); });
+  task_queue_->PostTask([this] { ResetRecStats(); });
   // Start a periodic timer based on task queue if not already done by the
   // playout side.
   if (!playing_) {
@@ -388,15 +399,15 @@
 }
 
 void AudioDeviceBuffer::StartPeriodicLogging() {
-  task_queue_.PostTask([this] { LogStats(AudioDeviceBuffer::LOG_START); });
+  task_queue_->PostTask([this] { LogStats(AudioDeviceBuffer::LOG_START); });
 }
 
 void AudioDeviceBuffer::StopPeriodicLogging() {
-  task_queue_.PostTask([this] { LogStats(AudioDeviceBuffer::LOG_STOP); });
+  task_queue_->PostTask([this] { LogStats(AudioDeviceBuffer::LOG_STOP); });
 }
 
 void AudioDeviceBuffer::LogStats(LogState state) {
-  RTC_DCHECK_RUN_ON(&task_queue_);
+  RTC_DCHECK_RUN_ON(task_queue_.get());
   int64_t now_time = rtc::TimeMillis();
 
   if (state == AudioDeviceBuffer::LOG_START) {
@@ -497,20 +508,20 @@
   RTC_DCHECK_GT(time_to_wait_ms, 0) << "Invalid timer interval";
 
   // Keep posting new (delayed) tasks until state is changed to kLogStop.
-  task_queue_.PostDelayedTask(
+  task_queue_->PostDelayedTask(
       [this] { AudioDeviceBuffer::LogStats(AudioDeviceBuffer::LOG_ACTIVE); },
       TimeDelta::Millis(time_to_wait_ms));
 }
 
 void AudioDeviceBuffer::ResetRecStats() {
-  RTC_DCHECK_RUN_ON(&task_queue_);
+  RTC_DCHECK_RUN_ON(task_queue_.get());
   last_stats_.ResetRecStats();
   MutexLock lock(&lock_);
   stats_.ResetRecStats();
 }
 
 void AudioDeviceBuffer::ResetPlayStats() {
-  RTC_DCHECK_RUN_ON(&task_queue_);
+  RTC_DCHECK_RUN_ON(task_queue_.get());
   last_stats_.ResetPlayStats();
   MutexLock lock(&lock_);
   stats_.ResetPlayStats();
diff --git a/modules/audio_device/audio_device_buffer.h b/modules/audio_device/audio_device_buffer.h
index 1260a24..b96696e 100644
--- a/modules/audio_device/audio_device_buffer.h
+++ b/modules/audio_device/audio_device_buffer.h
@@ -15,13 +15,14 @@
 #include <stdint.h>
 
 #include <atomic>
+#include <memory>
 
 #include "api/sequence_checker.h"
+#include "api/task_queue/task_queue_base.h"
 #include "api/task_queue/task_queue_factory.h"
 #include "modules/audio_device/include/audio_device_defines.h"
 #include "rtc_base/buffer.h"
 #include "rtc_base/synchronization/mutex.h"
-#include "rtc_base/task_queue.h"
 #include "rtc_base/thread_annotations.h"
 #include "rtc_base/timestamp_aligner.h"
 
@@ -158,7 +159,7 @@
   // Task queue used to invoke LogStats() periodically. Tasks are executed on a
   // worker thread but it does not necessarily have to be the same thread for
   // each task.
-  rtc::TaskQueue task_queue_;
+  std::unique_ptr<TaskQueueBase, TaskQueueDeleter> task_queue_;
 
   // Raw pointer to AudioTransport instance. Supplied to RegisterAudioCallback()
   // and it must outlive this object. It is not possible to change this member