Reland "Migrate TestAudioDeviceModule on AudioDeviceModuleImpl"

This CL will add AudioDeviceBuffer into the SUT increasing test coverage
for audio quality regression detection.

This reverts commit b035dcc0a274e6cdde3e0fc465244bc0e9e3d70e.

Reason for revert: reland with a fix

Original change's description:
> Revert "Reland "Migrate TestAudioDeviceModule on AudioDeviceModuleImpl""
>
> This reverts commit eeae96299784515f573379a64655eb07a5973a3a.
>
> Reason for revert: breaks WebRTC Chromium FYI ios-device
> https://ci.chromium.org/ui/p/chromium/builders/webrtc.fyi/WebRTC%20Chromium%20FYI%20ios-device/14896/overview
>
> Original change's description:
> > Reland "Migrate TestAudioDeviceModule on AudioDeviceModuleImpl"
> >
> > This reverts commit 69c8d3c843326aff9dee32cc639741c1cd7f8ae9.
> >
> > Reason for revert: Reland with a fix
> >
> > Original change's description:
> > > Revert "Migrate TestAudioDeviceModule on AudioDeviceModuleImpl"
> > >
> > > This reverts commit e42bf81486d2f08b6dcbf1442287202e937ce52b.
> > >
> > > Reason for revert: Breaks iOS simulator bots and thus blocks chromium roll, https://chromium-review.googlesource.com/c/chromium/src/+/4433814
> > >
> > > Original change's description:
> > > > Migrate TestAudioDeviceModule on AudioDeviceModuleImpl
> > > >
> > > > Bug: b/272350185
> > > > Change-Id: Ia3d85d6fa3b0d4809e987a39d60d3eb022687132
> > > > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/300363
> > > > Commit-Queue: Artem Titov <titovartem@webrtc.org>
> > > > Reviewed-by: Henrik Andreassson <henrika@webrtc.org>
> > > > Cr-Commit-Position: refs/heads/main@{#39877}
> > >
> > > Bug: b/272350185
> > > Change-Id: I1e3b542fc1278797f283afedeae01cbb7412d353
> > > No-Presubmit: true
> > > No-Tree-Checks: true
> > > No-Try: true
> > > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/301701
> > > Commit-Queue: Jeremy Leconte <jleconte@google.com>
> > > Bot-Commit: rubber-stamper@appspot.gserviceaccount.com <rubber-stamper@appspot.gserviceaccount.com>
> > > Reviewed-by: Jeremy Leconte <jleconte@google.com>
> > > Auto-Submit: Christoffer Jansson <jansson@google.com>
> > > Owners-Override: Christoffer Jansson <jansson@google.com>
> > > Cr-Commit-Position: refs/heads/main@{#39881}
> >
> > Bug: b/272350185
> > Change-Id: I809466306b2e1fd54c44b90311059c98a53ef8ee
> > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/301704
> > Reviewed-by: Henrik Andreassson <henrika@webrtc.org>
> > Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
> > Commit-Queue: Artem Titov <titovartem@webrtc.org>
> > Cr-Commit-Position: refs/heads/main@{#39936}
>
> Bug: b/272350185
> Change-Id: If0a10717bf14a0a618e52728fc3a61b9c55f3bd2
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/303460
> Commit-Queue: Jeremy Leconte <jleconte@google.com>
> Owners-Override: Jeremy Leconte <jleconte@google.com>
> Bot-Commit: rubber-stamper@appspot.gserviceaccount.com <rubber-stamper@appspot.gserviceaccount.com>
> Cr-Commit-Position: refs/heads/main@{#39947}

Bug: b/272350185
Change-Id: I7cf7c6bc25561f4eb722957f318c2af9ce20726d
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/311101
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Tomas Gunnarsson <tommi@webrtc.org>
Commit-Queue: Artem Titov <titovartem@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40387}
diff --git a/modules/audio_device/test_audio_device_impl.cc b/modules/audio_device/test_audio_device_impl.cc
new file mode 100644
index 0000000..c5de40c
--- /dev/null
+++ b/modules/audio_device/test_audio_device_impl.cc
@@ -0,0 +1,212 @@
+/*
+ *  Copyright (c) 2023 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "modules/audio_device/test_audio_device_impl.h"
+
+#include <memory>
+#include <utility>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/task_queue/task_queue_factory.h"
+#include "api/units/time_delta.h"
+#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.h"
+#include "rtc_base/task_utils/repeating_task.h"
+
+namespace webrtc {
+namespace {
+
+constexpr int kFrameLengthUs = 10000;
+
+}
+
+TestAudioDevice::TestAudioDevice(
+    TaskQueueFactory* task_queue_factory,
+    std::unique_ptr<TestAudioDeviceModule::Capturer> capturer,
+    std::unique_ptr<TestAudioDeviceModule::Renderer> renderer,
+    float speed)
+    : task_queue_factory_(task_queue_factory),
+      capturer_(std::move(capturer)),
+      renderer_(std::move(renderer)),
+      process_interval_us_(kFrameLengthUs / speed),
+      audio_buffer_(nullptr),
+      rendering_(false),
+      capturing_(false) {
+  auto good_sample_rate = [](int sr) {
+    return sr == 8000 || sr == 16000 || sr == 32000 || sr == 44100 ||
+           sr == 48000;
+  };
+
+  if (renderer_) {
+    const int sample_rate = renderer_->SamplingFrequency();
+    playout_buffer_.resize(TestAudioDeviceModule::SamplesPerFrame(sample_rate) *
+                               renderer_->NumChannels(),
+                           0);
+    RTC_CHECK(good_sample_rate(sample_rate));
+  }
+  if (capturer_) {
+    RTC_CHECK(good_sample_rate(capturer_->SamplingFrequency()));
+  }
+}
+
+AudioDeviceGeneric::InitStatus TestAudioDevice::Init() {
+  task_queue_ =
+      std::make_unique<rtc::TaskQueue>(task_queue_factory_->CreateTaskQueue(
+          "TestAudioDeviceModuleImpl", TaskQueueFactory::Priority::NORMAL));
+
+  RepeatingTaskHandle::Start(task_queue_->Get(), [this]() {
+    ProcessAudio();
+    return TimeDelta::Micros(process_interval_us_);
+  });
+  return InitStatus::OK;
+}
+
+int32_t TestAudioDevice::PlayoutIsAvailable(bool& available) {
+  MutexLock lock(&lock_);
+  available = renderer_ != nullptr;
+  return 0;
+}
+
+int32_t TestAudioDevice::InitPlayout() {
+  MutexLock lock(&lock_);
+
+  if (rendering_) {
+    return -1;
+  }
+
+  if (audio_buffer_ != nullptr && renderer_ != nullptr) {
+    // Update webrtc audio buffer with the selected parameters
+    audio_buffer_->SetPlayoutSampleRate(renderer_->SamplingFrequency());
+    audio_buffer_->SetPlayoutChannels(renderer_->NumChannels());
+  }
+  rendering_initialized_ = true;
+  return 0;
+}
+
+bool TestAudioDevice::PlayoutIsInitialized() const {
+  MutexLock lock(&lock_);
+  return rendering_initialized_;
+}
+
+int32_t TestAudioDevice::StartPlayout() {
+  MutexLock lock(&lock_);
+  RTC_CHECK(renderer_);
+  rendering_ = true;
+  return 0;
+}
+
+int32_t TestAudioDevice::StopPlayout() {
+  MutexLock lock(&lock_);
+  rendering_ = false;
+  return 0;
+}
+
+int32_t TestAudioDevice::RecordingIsAvailable(bool& available) {
+  MutexLock lock(&lock_);
+  available = capturer_ != nullptr;
+  return 0;
+}
+
+int32_t TestAudioDevice::InitRecording() {
+  MutexLock lock(&lock_);
+
+  if (capturing_) {
+    return -1;
+  }
+
+  if (audio_buffer_ != nullptr && capturer_ != nullptr) {
+    // Update webrtc audio buffer with the selected parameters
+    audio_buffer_->SetRecordingSampleRate(capturer_->SamplingFrequency());
+    audio_buffer_->SetRecordingChannels(capturer_->NumChannels());
+  }
+  capturing_initialized_ = true;
+  return 0;
+}
+
+bool TestAudioDevice::RecordingIsInitialized() const {
+  MutexLock lock(&lock_);
+  return capturing_initialized_;
+}
+
+int32_t TestAudioDevice::StartRecording() {
+  MutexLock lock(&lock_);
+  RTC_CHECK(capturer_);
+  capturing_ = true;
+  return 0;
+}
+
+int32_t TestAudioDevice::StopRecording() {
+  MutexLock lock(&lock_);
+  capturing_ = false;
+  return 0;
+}
+
+bool TestAudioDevice::Playing() const {
+  MutexLock lock(&lock_);
+  return rendering_;
+}
+
+bool TestAudioDevice::Recording() const {
+  MutexLock lock(&lock_);
+  return capturing_;
+}
+
+void TestAudioDevice::ProcessAudio() {
+  MutexLock lock(&lock_);
+  if (audio_buffer_ == nullptr) {
+    return;
+  }
+  if (capturing_) {
+    // Capture 10ms of audio. 2 bytes per sample.
+    const bool keep_capturing = capturer_->Capture(&recording_buffer_);
+    if (recording_buffer_.size() > 0) {
+      audio_buffer_->SetRecordedBuffer(
+          recording_buffer_.data(),
+          recording_buffer_.size() / capturer_->NumChannels(),
+          absl::make_optional(rtc::TimeNanos()));
+      audio_buffer_->DeliverRecordedData();
+    }
+    if (!keep_capturing) {
+      capturing_ = false;
+    }
+  }
+  if (rendering_) {
+    const int sampling_frequency = renderer_->SamplingFrequency();
+    int32_t samples_per_channel = audio_buffer_->RequestPlayoutData(
+        TestAudioDeviceModule::SamplesPerFrame(sampling_frequency));
+    audio_buffer_->GetPlayoutData(playout_buffer_.data());
+    size_t samples_out = samples_per_channel * renderer_->NumChannels();
+    RTC_CHECK_LE(samples_out, playout_buffer_.size());
+    const bool keep_rendering = renderer_->Render(
+        rtc::ArrayView<const int16_t>(playout_buffer_.data(), samples_out));
+    if (!keep_rendering) {
+      rendering_ = false;
+    }
+  }
+}
+
+void TestAudioDevice::AttachAudioBuffer(AudioDeviceBuffer* audio_buffer) {
+  MutexLock lock(&lock_);
+  RTC_DCHECK(audio_buffer || audio_buffer_);
+  audio_buffer_ = audio_buffer;
+
+  if (renderer_ != nullptr) {
+    audio_buffer_->SetPlayoutSampleRate(renderer_->SamplingFrequency());
+    audio_buffer_->SetPlayoutChannels(renderer_->NumChannels());
+  }
+  if (capturer_ != nullptr) {
+    audio_buffer_->SetRecordingSampleRate(capturer_->SamplingFrequency());
+    audio_buffer_->SetRecordingChannels(capturer_->NumChannels());
+  }
+}
+
+}  // namespace webrtc