Refactor FakeAudioDevice to have separate methods for starting recording and playout.
Also, change FakeAudioDevice to generate a sine tone instead of using a file.

TBR=henrika@webrtc.org, stefan@webrtc.org

BUG=webrtc:7080

Review-Url: https://codereview.webrtc.org/2652803002
Cr-Commit-Position: refs/heads/master@{#16385}
diff --git a/webrtc/call/call_perf_tests.cc b/webrtc/call/call_perf_tests.cc
index 782b45c..b6a8fe6 100644
--- a/webrtc/call/call_perf_tests.cc
+++ b/webrtc/call/call_perf_tests.cc
@@ -146,11 +146,7 @@
   metrics::Reset();
   VoiceEngine* voice_engine = VoiceEngine::Create();
   VoEBase* voe_base = VoEBase::GetInterface(voice_engine);
-  const std::string audio_filename =
-      test::ResourcePath("voice_engine/audio_long16", "pcm");
-  ASSERT_STRNE("", audio_filename.c_str());
-  FakeAudioDevice fake_audio_device(Clock::GetRealTimeClock(), audio_filename,
-                                    audio_rtp_speed);
+  FakeAudioDevice fake_audio_device(audio_rtp_speed, 48000, 256);
   EXPECT_EQ(0, voe_base->Init(&fake_audio_device, nullptr, decoder_factory_));
   VoEBase::ChannelConfig config;
   config.enable_voice_pacing = true;
@@ -264,16 +260,14 @@
 
   Start();
 
-  fake_audio_device.Start();
+  audio_send_stream->Start();
   audio_receive_stream->Start();
-  EXPECT_EQ(0, voe_base->StartSend(send_channel_id));
 
   EXPECT_TRUE(observer.Wait())
       << "Timed out while waiting for audio and video to be synchronized.";
 
-  EXPECT_EQ(0, voe_base->StopSend(send_channel_id));
-  EXPECT_EQ(0, voe_base->StopPlayout(recv_channel_id));
-  fake_audio_device.Stop();
+  audio_send_stream->Stop();
+  audio_receive_stream->Stop();
 
   Stop();
   video_send_transport.StopSending();
diff --git a/webrtc/modules/audio_device/include/fake_audio_device.h b/webrtc/modules/audio_device/include/fake_audio_device.h
index 98fd2f4..a28ad86 100644
--- a/webrtc/modules/audio_device/include/fake_audio_device.h
+++ b/webrtc/modules/audio_device/include/fake_audio_device.h
@@ -21,6 +21,8 @@
   virtual ~FakeAudioDeviceModule() {}
   virtual int32_t AddRef() const { return 0; }
   virtual int32_t Release() const { return 0; }
+
+ private:
   virtual int32_t RegisterEventObserver(AudioDeviceObserver* eventCallback) {
     return 0;
   }
@@ -121,7 +123,10 @@
   virtual int32_t PlayoutBuffer(BufferType* type, uint16_t* sizeMS) const {
     return 0;
   }
-  virtual int32_t PlayoutDelay(uint16_t* delayMS) const { return 0; }
+  virtual int32_t PlayoutDelay(uint16_t* delayMS) const {
+    *delayMS = 0;
+    return 0;
+  }
   virtual int32_t RecordingDelay(uint16_t* delayMS) const { return 0; }
   virtual int32_t CPULoad(uint16_t* load) const { return 0; }
   virtual int32_t StartRawOutputFileRecording(
diff --git a/webrtc/test/BUILD.gn b/webrtc/test/BUILD.gn
index 9893814..352eb37 100644
--- a/webrtc/test/BUILD.gn
+++ b/webrtc/test/BUILD.gn
@@ -332,7 +332,6 @@
     "../modules/audio_device:mock_audio_device",
     "../modules/audio_mixer:audio_mixer_impl",
     "../modules/audio_processing",
-    "../modules/media_file",
     "../modules/video_capture:video_capture",
     "../modules/video_capture:video_capture_module",
     "../video",
diff --git a/webrtc/test/call_test.cc b/webrtc/test/call_test.cc
index c1c7355..87bbea7 100644
--- a/webrtc/test/call_test.cc
+++ b/webrtc/test/call_test.cc
@@ -140,16 +140,10 @@
   for (VideoReceiveStream* video_recv_stream : video_receive_streams_)
     video_recv_stream->Start();
   if (audio_send_stream_) {
-    fake_send_audio_device_->Start();
     audio_send_stream_->Start();
-    EXPECT_EQ(0, voe_send_.base->StartSend(voe_send_.channel_id));
   }
   for (AudioReceiveStream* audio_recv_stream : audio_receive_streams_)
     audio_recv_stream->Start();
-  if (!audio_receive_streams_.empty()) {
-    fake_recv_audio_device_->Start();
-    EXPECT_EQ(0, voe_recv_.base->StartPlayout(voe_recv_.channel_id));
-  }
   for (FlexfecReceiveStream* flexfec_recv_stream : flexfec_receive_streams_)
     flexfec_recv_stream->Start();
   if (frame_generator_capturer_.get() != NULL)
@@ -161,15 +155,9 @@
     frame_generator_capturer_->Stop();
   for (FlexfecReceiveStream* flexfec_recv_stream : flexfec_receive_streams_)
     flexfec_recv_stream->Stop();
-  if (!audio_receive_streams_.empty()) {
-    fake_recv_audio_device_->Stop();
-    EXPECT_EQ(0, voe_recv_.base->StopPlayout(voe_recv_.channel_id));
-  }
   for (AudioReceiveStream* audio_recv_stream : audio_receive_streams_)
     audio_recv_stream->Stop();
   if (audio_send_stream_) {
-    fake_send_audio_device_->Stop();
-    EXPECT_EQ(0, voe_send_.base->StopSend(voe_send_.channel_id));
     audio_send_stream_->Stop();
   }
   for (VideoReceiveStream* video_recv_stream : video_receive_streams_)
@@ -309,12 +297,8 @@
 }
 
 void CallTest::CreateFakeAudioDevices() {
-  fake_send_audio_device_.reset(new FakeAudioDevice(
-      clock_, test::ResourcePath("voice_engine/audio_long16", "pcm"),
-      DriftingClock::kNoDrift));
-  fake_recv_audio_device_.reset(new FakeAudioDevice(
-      clock_, test::ResourcePath("voice_engine/audio_long16", "pcm"),
-      DriftingClock::kNoDrift));
+  fake_send_audio_device_.reset(new FakeAudioDevice(1.f, 48000, 256));
+  fake_recv_audio_device_.reset(new FakeAudioDevice(1.f, 48000, 256));
 }
 
 void CallTest::CreateVideoStreams() {
diff --git a/webrtc/test/fake_audio_device.cc b/webrtc/test/fake_audio_device.cc
index 9e5e95f..623ff51 100644
--- a/webrtc/test/fake_audio_device.cc
+++ b/webrtc/test/fake_audio_device.cc
@@ -12,49 +12,104 @@
 
 #include <algorithm>
 
-#include "webrtc/base/platform_thread.h"
-#include "webrtc/modules/media_file/media_file_utility.h"
-#include "webrtc/system_wrappers/include/clock.h"
+#include "webrtc/base/array_view.h"
+#include "webrtc/base/checks.h"
+#include "webrtc/base/random.h"
 #include "webrtc/system_wrappers/include/event_wrapper.h"
-#include "webrtc/system_wrappers/include/file_wrapper.h"
-#include "webrtc/test/gtest.h"
 
 namespace webrtc {
+
+namespace {
+
+constexpr int kFrameLengthMs = 10;
+constexpr int kFramesPerSecond = 1000 / kFrameLengthMs;
+
+}  // namespace
 namespace test {
 
-FakeAudioDevice::FakeAudioDevice(Clock* clock,
-                                 const std::string& filename,
-                                 float speed)
-    : audio_callback_(NULL),
-      capturing_(false),
-      captured_audio_(),
-      playout_buffer_(),
+// Assuming 10ms audio packets..
+class FakeAudioDevice::PulsedNoiseCapturer {
+ public:
+  PulsedNoiseCapturer(size_t num_samples_per_frame, int16_t max_amplitude)
+      : fill_with_zero_(false),
+        random_generator_(1),
+        max_amplitude_(max_amplitude),
+        random_audio_(num_samples_per_frame),
+        silent_audio_(num_samples_per_frame, 0) {
+    RTC_DCHECK_GT(max_amplitude, 0);
+  }
+
+  rtc::ArrayView<const int16_t> Capture() {
+    fill_with_zero_ = !fill_with_zero_;
+    if (!fill_with_zero_) {
+      std::generate(random_audio_.begin(), random_audio_.end(), [&]() {
+        return random_generator_.Rand(-max_amplitude_, max_amplitude_);
+      });
+    }
+    return fill_with_zero_ ? silent_audio_ : random_audio_;
+  }
+
+ private:
+  bool fill_with_zero_;
+  Random random_generator_;
+  const int16_t max_amplitude_;
+  std::vector<int16_t> random_audio_;
+  std::vector<int16_t> silent_audio_;
+};
+
+FakeAudioDevice::FakeAudioDevice(float speed,
+                                 int sampling_frequency_in_hz,
+                                 int16_t max_amplitude)
+    : sampling_frequency_in_hz_(sampling_frequency_in_hz),
+      num_samples_per_frame_(
+          rtc::CheckedDivExact(sampling_frequency_in_hz_, kFramesPerSecond)),
       speed_(speed),
-      last_playout_ms_(-1),
-      clock_(clock, speed),
+      audio_callback_(nullptr),
+      rendering_(false),
+      capturing_(false),
+      capturer_(new FakeAudioDevice::PulsedNoiseCapturer(num_samples_per_frame_,
+                                                         max_amplitude)),
+      playout_buffer_(num_samples_per_frame_, 0),
       tick_(EventTimerWrapper::Create()),
-      thread_(FakeAudioDevice::Run, this, "FakeAudioDevice"),
-      file_utility_(new ModuleFileUtility(0)),
-      input_stream_(FileWrapper::Create()) {
-  memset(captured_audio_, 0, sizeof(captured_audio_));
-  memset(playout_buffer_, 0, sizeof(playout_buffer_));
-  // Open audio input file as read-only and looping.
-  EXPECT_TRUE(input_stream_->OpenFile(filename.c_str(), true)) << filename;
+      thread_(FakeAudioDevice::Run, this, "FakeAudioDevice") {
+  RTC_DCHECK(
+      sampling_frequency_in_hz == 8000 || sampling_frequency_in_hz == 16000 ||
+      sampling_frequency_in_hz == 32000 || sampling_frequency_in_hz == 44100 ||
+      sampling_frequency_in_hz == 48000);
 }
 
 FakeAudioDevice::~FakeAudioDevice() {
-  Stop();
-
+  StopPlayout();
+  StopRecording();
   thread_.Stop();
 }
 
-int32_t FakeAudioDevice::Init() {
+int32_t FakeAudioDevice::StartPlayout() {
   rtc::CritScope cs(&lock_);
-  if (file_utility_->InitPCMReading(*input_stream_.get()) != 0)
-    return -1;
+  rendering_ = true;
+  return 0;
+}
 
-  if (!tick_->StartTimer(true, 10 / speed_))
-    return -1;
+int32_t FakeAudioDevice::StopPlayout() {
+  rtc::CritScope cs(&lock_);
+  rendering_ = false;
+  return 0;
+}
+
+int32_t FakeAudioDevice::StartRecording() {
+  rtc::CritScope cs(&lock_);
+  capturing_ = true;
+  return 0;
+}
+
+int32_t FakeAudioDevice::StopRecording() {
+  rtc::CritScope cs(&lock_);
+  capturing_ = false;
+  return 0;
+}
+
+int32_t FakeAudioDevice::Init() {
+  RTC_CHECK(tick_->StartTimer(true, kFrameLengthMs / speed_));
   thread_.Start();
   thread_.SetPriority(rtc::kHighPriority);
   return 0;
@@ -62,18 +117,14 @@
 
 int32_t FakeAudioDevice::RegisterAudioCallback(AudioTransport* callback) {
   rtc::CritScope cs(&lock_);
+  RTC_DCHECK(callback || audio_callback_ != nullptr);
   audio_callback_ = callback;
   return 0;
 }
 
 bool FakeAudioDevice::Playing() const {
   rtc::CritScope cs(&lock_);
-  return capturing_;
-}
-
-int32_t FakeAudioDevice::PlayoutDelay(uint16_t* delay_ms) const {
-  *delay_ms = 0;
-  return 0;
+  return rendering_;
 }
 
 bool FakeAudioDevice::Recording() const {
@@ -82,65 +133,33 @@
 }
 
 bool FakeAudioDevice::Run(void* obj) {
-  static_cast<FakeAudioDevice*>(obj)->CaptureAudio();
+  static_cast<FakeAudioDevice*>(obj)->ProcessAudio();
   return true;
 }
 
-void FakeAudioDevice::CaptureAudio() {
+void FakeAudioDevice::ProcessAudio() {
   {
     rtc::CritScope cs(&lock_);
     if (capturing_) {
-      int bytes_read = file_utility_->ReadPCMData(
-          *input_stream_.get(), captured_audio_, kBufferSizeBytes);
-      if (bytes_read <= 0)
-        return;
-      // 2 bytes per sample.
-      size_t num_samples = static_cast<size_t>(bytes_read / 2);
-      uint32_t new_mic_level;
-      EXPECT_EQ(0,
-                audio_callback_->RecordedDataIsAvailable(captured_audio_,
-                                                         num_samples,
-                                                         2,
-                                                         1,
-                                                         kFrequencyHz,
-                                                         0,
-                                                         0,
-                                                         0,
-                                                         false,
-                                                         new_mic_level));
-      size_t samples_needed = kFrequencyHz / 100;
-      int64_t now_ms = clock_.TimeInMilliseconds();
-      uint32_t time_since_last_playout_ms = now_ms - last_playout_ms_;
-      if (last_playout_ms_ > 0 && time_since_last_playout_ms > 0) {
-        samples_needed = std::min(
-            static_cast<size_t>(kFrequencyHz / time_since_last_playout_ms),
-            kBufferSizeBytes / 2);
-      }
+      // Capture 10ms of audio. 2 bytes per sample.
+      rtc::ArrayView<const int16_t> audio_data = capturer_->Capture();
+      uint32_t new_mic_level = 0;
+      audio_callback_->RecordedDataIsAvailable(
+          audio_data.data(), audio_data.size(), 2, 1, sampling_frequency_in_hz_,
+          0, 0, 0, false, new_mic_level);
+    }
+    if (rendering_) {
       size_t samples_out = 0;
       int64_t elapsed_time_ms = -1;
       int64_t ntp_time_ms = -1;
-      EXPECT_EQ(0,
-                audio_callback_->NeedMorePlayData(samples_needed,
-                                                  2,
-                                                  1,
-                                                  kFrequencyHz,
-                                                  playout_buffer_,
-                                                  samples_out,
-                                                  &elapsed_time_ms,
-                                                  &ntp_time_ms));
+      audio_callback_->NeedMorePlayData(
+          num_samples_per_frame_, 2, 1, sampling_frequency_in_hz_,
+          playout_buffer_.data(), samples_out, &elapsed_time_ms, &ntp_time_ms);
     }
   }
   tick_->Wait(WEBRTC_EVENT_INFINITE);
 }
 
-void FakeAudioDevice::Start() {
-  rtc::CritScope cs(&lock_);
-  capturing_ = true;
-}
 
-void FakeAudioDevice::Stop() {
-  rtc::CritScope cs(&lock_);
-  capturing_ = false;
-}
 }  // namespace test
 }  // namespace webrtc
diff --git a/webrtc/test/fake_audio_device.h b/webrtc/test/fake_audio_device.h
index 77a74ba..4daeab4 100644
--- a/webrtc/test/fake_audio_device.h
+++ b/webrtc/test/fake_audio_device.h
@@ -12,58 +12,65 @@
 
 #include <memory>
 #include <string>
+#include <vector>
 
 #include "webrtc/base/criticalsection.h"
 #include "webrtc/base/platform_thread.h"
 #include "webrtc/modules/audio_device/include/fake_audio_device.h"
-#include "webrtc/test/drifting_clock.h"
 #include "webrtc/typedefs.h"
 
 namespace webrtc {
 
-class Clock;
 class EventTimerWrapper;
-class FileWrapper;
-class ModuleFileUtility;
 
 namespace test {
 
+// FakeAudioDevice implements an AudioDevice module that can act both as a
+// capturer and a renderer. It will use 10ms audio frames.
 class FakeAudioDevice : public FakeAudioDeviceModule {
  public:
-  FakeAudioDevice(Clock* clock, const std::string& filename, float speed);
+  // Creates a new FakeAudioDevice. When capturing or playing, 10 ms audio
+  // frames will be processed every 100ms / |speed|.
+  // |sampling_frequency_in_hz| can be 8, 16, 32, 44.1 or 48kHz.
+  // When recording is started, it will generates a signal where every second
+  // frame is zero and every second frame is evenly distributed random noise
+  // with max amplitude |max_amplitude|.
+  FakeAudioDevice(float speed,
+                  int sampling_frequency_in_hz,
+                  int16_t max_amplitude);
+  ~FakeAudioDevice() override;
 
-  virtual ~FakeAudioDevice();
-
+ private:
   int32_t Init() override;
   int32_t RegisterAudioCallback(AudioTransport* callback) override;
 
+  int32_t StartPlayout() override;
+  int32_t StopPlayout() override;
+  int32_t StartRecording() override;
+  int32_t StopRecording() override;
+
   bool Playing() const override;
-  int32_t PlayoutDelay(uint16_t* delay_ms) const override;
   bool Recording() const override;
 
-  void Start();
-  void Stop();
-
- private:
   static bool Run(void* obj);
-  void CaptureAudio();
+  void ProcessAudio();
 
-  static const uint32_t kFrequencyHz = 16000;
-  static const size_t kBufferSizeBytes = 2 * kFrequencyHz;
-
-  AudioTransport* audio_callback_;
-  bool capturing_;
-  int8_t captured_audio_[kBufferSizeBytes];
-  int8_t playout_buffer_[kBufferSizeBytes];
+  const int sampling_frequency_in_hz_;
+  const size_t num_samples_per_frame_;
   const float speed_;
-  int64_t last_playout_ms_;
 
-  DriftingClock clock_;
-  std::unique_ptr<EventTimerWrapper> tick_;
   rtc::CriticalSection lock_;
+  AudioTransport* audio_callback_ GUARDED_BY(lock_);
+  bool rendering_ GUARDED_BY(lock_);
+  bool capturing_ GUARDED_BY(lock_);
+
+  class PulsedNoiseCapturer;
+  const std::unique_ptr<PulsedNoiseCapturer> capturer_ GUARDED_BY(lock_);
+
+  std::vector<int16_t> playout_buffer_ GUARDED_BY(lock_);
+
+  std::unique_ptr<EventTimerWrapper> tick_;
   rtc::PlatformThread thread_;
-  std::unique_ptr<ModuleFileUtility> file_utility_;
-  std::unique_ptr<FileWrapper> input_stream_;
 };
 }  // namespace test
 }  // namespace webrtc