summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/pc/test/fake_audio_capture_module.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/pc/test/fake_audio_capture_module.cc')
-rw-r--r--third_party/libwebrtc/pc/test/fake_audio_capture_module.cc521
1 files changed, 521 insertions, 0 deletions
diff --git a/third_party/libwebrtc/pc/test/fake_audio_capture_module.cc b/third_party/libwebrtc/pc/test/fake_audio_capture_module.cc
new file mode 100644
index 0000000000..132328291c
--- /dev/null
+++ b/third_party/libwebrtc/pc/test/fake_audio_capture_module.cc
@@ -0,0 +1,521 @@
+/*
+ * Copyright 2012 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 "pc/test/fake_audio_capture_module.h"
+
+#include <string.h>
+
+#include "api/make_ref_counted.h"
+#include "api/units/time_delta.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/thread.h"
+#include "rtc_base/time_utils.h"
+
+using ::webrtc::TimeDelta;
+
+// Audio sample value that is high enough that it doesn't occur naturally when
+// frames are being faked. E.g. NetEq will not generate this large sample value
+// unless it has received an audio frame containing a sample of this value.
+// Even simpler buffers would likely just contain audio sample values of 0.
+static const int kHighSampleValue = 10000;
+
+// Constants here are derived by running VoE using a real ADM.
+// The constants correspond to 10ms of mono audio at 44kHz.
+static const int kTimePerFrameMs = 10;
+static const uint8_t kNumberOfChannels = 1;
+static const int kSamplesPerSecond = 44000;
+static const int kTotalDelayMs = 0;
+static const int kClockDriftMs = 0;
+static const uint32_t kMaxVolume = 14392;
+
+FakeAudioCaptureModule::FakeAudioCaptureModule()
+ : audio_callback_(nullptr),
+ recording_(false),
+ playing_(false),
+ play_is_initialized_(false),
+ rec_is_initialized_(false),
+ current_mic_level_(kMaxVolume),
+ started_(false),
+ next_frame_time_(0),
+ frames_received_(0) {
+ process_thread_checker_.Detach();
+}
+
+FakeAudioCaptureModule::~FakeAudioCaptureModule() {
+ if (process_thread_) {
+ process_thread_->Stop();
+ }
+}
+
+rtc::scoped_refptr<FakeAudioCaptureModule> FakeAudioCaptureModule::Create() {
+ auto capture_module = rtc::make_ref_counted<FakeAudioCaptureModule>();
+ if (!capture_module->Initialize()) {
+ return nullptr;
+ }
+ return capture_module;
+}
+
+int FakeAudioCaptureModule::frames_received() const {
+ webrtc::MutexLock lock(&mutex_);
+ return frames_received_;
+}
+
+int32_t FakeAudioCaptureModule::ActiveAudioLayer(
+ AudioLayer* /*audio_layer*/) const {
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::RegisterAudioCallback(
+ webrtc::AudioTransport* audio_callback) {
+ webrtc::MutexLock lock(&mutex_);
+ audio_callback_ = audio_callback;
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::Init() {
+ // Initialize is called by the factory method. Safe to ignore this Init call.
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::Terminate() {
+ // Clean up in the destructor. No action here, just success.
+ return 0;
+}
+
+bool FakeAudioCaptureModule::Initialized() const {
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+int16_t FakeAudioCaptureModule::PlayoutDevices() {
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+int16_t FakeAudioCaptureModule::RecordingDevices() {
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::PlayoutDeviceName(
+ uint16_t /*index*/,
+ char /*name*/[webrtc::kAdmMaxDeviceNameSize],
+ char /*guid*/[webrtc::kAdmMaxGuidSize]) {
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::RecordingDeviceName(
+ uint16_t /*index*/,
+ char /*name*/[webrtc::kAdmMaxDeviceNameSize],
+ char /*guid*/[webrtc::kAdmMaxGuidSize]) {
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetPlayoutDevice(uint16_t /*index*/) {
+ // No playout device, just playing from file. Return success.
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetPlayoutDevice(WindowsDeviceType /*device*/) {
+ if (play_is_initialized_) {
+ return -1;
+ }
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetRecordingDevice(uint16_t /*index*/) {
+ // No recording device, just dropping audio. Return success.
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetRecordingDevice(
+ WindowsDeviceType /*device*/) {
+ if (rec_is_initialized_) {
+ return -1;
+ }
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::PlayoutIsAvailable(bool* /*available*/) {
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::InitPlayout() {
+ play_is_initialized_ = true;
+ return 0;
+}
+
+bool FakeAudioCaptureModule::PlayoutIsInitialized() const {
+ return play_is_initialized_;
+}
+
+int32_t FakeAudioCaptureModule::RecordingIsAvailable(bool* /*available*/) {
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::InitRecording() {
+ rec_is_initialized_ = true;
+ return 0;
+}
+
+bool FakeAudioCaptureModule::RecordingIsInitialized() const {
+ return rec_is_initialized_;
+}
+
+int32_t FakeAudioCaptureModule::StartPlayout() {
+ if (!play_is_initialized_) {
+ return -1;
+ }
+ {
+ webrtc::MutexLock lock(&mutex_);
+ playing_ = true;
+ }
+ bool start = true;
+ UpdateProcessing(start);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::StopPlayout() {
+ bool start = false;
+ {
+ webrtc::MutexLock lock(&mutex_);
+ playing_ = false;
+ start = ShouldStartProcessing();
+ }
+ UpdateProcessing(start);
+ return 0;
+}
+
+bool FakeAudioCaptureModule::Playing() const {
+ webrtc::MutexLock lock(&mutex_);
+ return playing_;
+}
+
+int32_t FakeAudioCaptureModule::StartRecording() {
+ if (!rec_is_initialized_) {
+ return -1;
+ }
+ {
+ webrtc::MutexLock lock(&mutex_);
+ recording_ = true;
+ }
+ bool start = true;
+ UpdateProcessing(start);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::StopRecording() {
+ bool start = false;
+ {
+ webrtc::MutexLock lock(&mutex_);
+ recording_ = false;
+ start = ShouldStartProcessing();
+ }
+ UpdateProcessing(start);
+ return 0;
+}
+
+bool FakeAudioCaptureModule::Recording() const {
+ webrtc::MutexLock lock(&mutex_);
+ return recording_;
+}
+
+int32_t FakeAudioCaptureModule::InitSpeaker() {
+ // No speaker, just playing from file. Return success.
+ return 0;
+}
+
+bool FakeAudioCaptureModule::SpeakerIsInitialized() const {
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::InitMicrophone() {
+ // No microphone, just playing from file. Return success.
+ return 0;
+}
+
+bool FakeAudioCaptureModule::MicrophoneIsInitialized() const {
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SpeakerVolumeIsAvailable(bool* /*available*/) {
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetSpeakerVolume(uint32_t /*volume*/) {
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SpeakerVolume(uint32_t* /*volume*/) const {
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::MaxSpeakerVolume(
+ uint32_t* /*max_volume*/) const {
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::MinSpeakerVolume(
+ uint32_t* /*min_volume*/) const {
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::MicrophoneVolumeIsAvailable(
+ bool* /*available*/) {
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetMicrophoneVolume(uint32_t volume) {
+ webrtc::MutexLock lock(&mutex_);
+ current_mic_level_ = volume;
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::MicrophoneVolume(uint32_t* volume) const {
+ webrtc::MutexLock lock(&mutex_);
+ *volume = current_mic_level_;
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::MaxMicrophoneVolume(
+ uint32_t* max_volume) const {
+ *max_volume = kMaxVolume;
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::MinMicrophoneVolume(
+ uint32_t* /*min_volume*/) const {
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SpeakerMuteIsAvailable(bool* /*available*/) {
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetSpeakerMute(bool /*enable*/) {
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SpeakerMute(bool* /*enabled*/) const {
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::MicrophoneMuteIsAvailable(bool* /*available*/) {
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetMicrophoneMute(bool /*enable*/) {
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::MicrophoneMute(bool* /*enabled*/) const {
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::StereoPlayoutIsAvailable(
+ bool* available) const {
+ // No recording device, just dropping audio. Stereo can be dropped just
+ // as easily as mono.
+ *available = true;
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetStereoPlayout(bool /*enable*/) {
+ // No recording device, just dropping audio. Stereo can be dropped just
+ // as easily as mono.
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::StereoPlayout(bool* /*enabled*/) const {
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::StereoRecordingIsAvailable(
+ bool* available) const {
+ // Keep thing simple. No stereo recording.
+ *available = false;
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetStereoRecording(bool enable) {
+ if (!enable) {
+ return 0;
+ }
+ return -1;
+}
+
+int32_t FakeAudioCaptureModule::StereoRecording(bool* /*enabled*/) const {
+ RTC_DCHECK_NOTREACHED();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::PlayoutDelay(uint16_t* delay_ms) const {
+ // No delay since audio frames are dropped.
+ *delay_ms = 0;
+ return 0;
+}
+
+bool FakeAudioCaptureModule::Initialize() {
+ // Set the send buffer samples high enough that it would not occur on the
+ // remote side unless a packet containing a sample of that magnitude has been
+ // sent to it. Note that the audio processing pipeline will likely distort the
+ // original signal.
+ SetSendBuffer(kHighSampleValue);
+ return true;
+}
+
+void FakeAudioCaptureModule::SetSendBuffer(int value) {
+ Sample* buffer_ptr = reinterpret_cast<Sample*>(send_buffer_);
+ const size_t buffer_size_in_samples =
+ sizeof(send_buffer_) / kNumberBytesPerSample;
+ for (size_t i = 0; i < buffer_size_in_samples; ++i) {
+ buffer_ptr[i] = value;
+ }
+}
+
+void FakeAudioCaptureModule::ResetRecBuffer() {
+ memset(rec_buffer_, 0, sizeof(rec_buffer_));
+}
+
+bool FakeAudioCaptureModule::CheckRecBuffer(int value) {
+ const Sample* buffer_ptr = reinterpret_cast<const Sample*>(rec_buffer_);
+ const size_t buffer_size_in_samples =
+ sizeof(rec_buffer_) / kNumberBytesPerSample;
+ for (size_t i = 0; i < buffer_size_in_samples; ++i) {
+ if (buffer_ptr[i] >= value)
+ return true;
+ }
+ return false;
+}
+
+bool FakeAudioCaptureModule::ShouldStartProcessing() {
+ return recording_ || playing_;
+}
+
+void FakeAudioCaptureModule::UpdateProcessing(bool start) {
+ if (start) {
+ if (!process_thread_) {
+ process_thread_ = rtc::Thread::Create();
+ process_thread_->Start();
+ }
+ process_thread_->PostTask([this] { StartProcessP(); });
+ } else {
+ if (process_thread_) {
+ process_thread_->Stop();
+ process_thread_.reset(nullptr);
+ process_thread_checker_.Detach();
+ }
+ webrtc::MutexLock lock(&mutex_);
+ started_ = false;
+ }
+}
+
+void FakeAudioCaptureModule::StartProcessP() {
+ RTC_DCHECK_RUN_ON(&process_thread_checker_);
+ {
+ webrtc::MutexLock lock(&mutex_);
+ if (started_) {
+ // Already started.
+ return;
+ }
+ }
+ ProcessFrameP();
+}
+
+void FakeAudioCaptureModule::ProcessFrameP() {
+ RTC_DCHECK_RUN_ON(&process_thread_checker_);
+ {
+ webrtc::MutexLock lock(&mutex_);
+ if (!started_) {
+ next_frame_time_ = rtc::TimeMillis();
+ started_ = true;
+ }
+
+ // Receive and send frames every kTimePerFrameMs.
+ if (playing_) {
+ ReceiveFrameP();
+ }
+ if (recording_) {
+ SendFrameP();
+ }
+ }
+
+ next_frame_time_ += kTimePerFrameMs;
+ const int64_t current_time = rtc::TimeMillis();
+ const int64_t wait_time =
+ (next_frame_time_ > current_time) ? next_frame_time_ - current_time : 0;
+ process_thread_->PostDelayedTask([this] { ProcessFrameP(); },
+ TimeDelta::Millis(wait_time));
+}
+
+void FakeAudioCaptureModule::ReceiveFrameP() {
+ RTC_DCHECK_RUN_ON(&process_thread_checker_);
+ if (!audio_callback_) {
+ return;
+ }
+ ResetRecBuffer();
+ size_t nSamplesOut = 0;
+ int64_t elapsed_time_ms = 0;
+ int64_t ntp_time_ms = 0;
+ if (audio_callback_->NeedMorePlayData(kNumberSamples, kNumberBytesPerSample,
+ kNumberOfChannels, kSamplesPerSecond,
+ rec_buffer_, nSamplesOut,
+ &elapsed_time_ms, &ntp_time_ms) != 0) {
+ RTC_DCHECK_NOTREACHED();
+ }
+ RTC_CHECK(nSamplesOut == kNumberSamples);
+
+ // The SetBuffer() function ensures that after decoding, the audio buffer
+ // should contain samples of similar magnitude (there is likely to be some
+ // distortion due to the audio pipeline). If one sample is detected to
+ // have the same or greater magnitude somewhere in the frame, an actual frame
+ // has been received from the remote side (i.e. faked frames are not being
+ // pulled).
+ if (CheckRecBuffer(kHighSampleValue)) {
+ ++frames_received_;
+ }
+}
+
+void FakeAudioCaptureModule::SendFrameP() {
+ RTC_DCHECK_RUN_ON(&process_thread_checker_);
+ if (!audio_callback_) {
+ return;
+ }
+ bool key_pressed = false;
+ uint32_t current_mic_level = current_mic_level_;
+ if (audio_callback_->RecordedDataIsAvailable(
+ send_buffer_, kNumberSamples, kNumberBytesPerSample,
+ kNumberOfChannels, kSamplesPerSecond, kTotalDelayMs, kClockDriftMs,
+ current_mic_level, key_pressed, current_mic_level) != 0) {
+ RTC_DCHECK_NOTREACHED();
+ }
+ current_mic_level_ = current_mic_level;
+}