Index: webrtc/modules/audio_processing/test/fake_recording_device.cc |
diff --git a/webrtc/modules/audio_processing/test/fake_recording_device.cc b/webrtc/modules/audio_processing/test/fake_recording_device.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..67ba34a3901e4b5fcd296683d8612625f8b9fbed |
--- /dev/null |
+++ b/webrtc/modules/audio_processing/test/fake_recording_device.cc |
@@ -0,0 +1,165 @@ |
+/* |
+ * Copyright (c) 2017 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 "webrtc/modules/audio_processing/test/fake_recording_device.h" |
+ |
+#include <algorithm> |
+ |
+#include "webrtc/rtc_base/logging.h" |
+#include "webrtc/rtc_base/ptr_util.h" |
+ |
+namespace webrtc { |
+namespace test { |
+ |
+namespace { |
+ |
+constexpr int16_t kInt16SampleMin = -32768; |
+constexpr int16_t kInt16SampleMax = 32767; |
+constexpr float kFloatSampleMin = -32768.f; |
+constexpr float kFloatSampleMax = 32767.0f; |
+ |
+} // namespace |
+ |
+// Abstract class for the different fake recording devices. |
+class FakeRecordingDeviceWorker { |
+ public: |
+ explicit FakeRecordingDeviceWorker(const int initial_mic_level) |
+ : mic_level_(initial_mic_level) {} |
+ int mic_level() const { return mic_level_; } |
+ void set_mic_level(const int level) { mic_level_ = level; } |
+ void set_undo_mic_level(const rtc::Optional<int> level) { |
+ undo_mic_level_ = level; |
+ } |
+ virtual ~FakeRecordingDeviceWorker() = default; |
+ virtual void ModifyBufferInt16(AudioFrame* buffer) = 0; |
+ virtual void ModifyBufferFloat(ChannelBuffer<float>* buffer) = 0; |
+ |
+ protected: |
+ // Mic level to simulate. |
+ int mic_level_; |
+ // Optional mic level to undo. |
+ rtc::Optional<int> undo_mic_level_; |
+}; |
+ |
+namespace { |
+ |
+// Identity fake recording device. The samples are not modified, which is |
+// equivalent to a constant gain curve at 1.0 - only used for testing. |
+class FakeRecordingDeviceIdentity final : public FakeRecordingDeviceWorker { |
+ public: |
+ explicit FakeRecordingDeviceIdentity(const int initial_mic_level) |
+ : FakeRecordingDeviceWorker(initial_mic_level) {} |
+ ~FakeRecordingDeviceIdentity() override = default; |
+ void ModifyBufferInt16(AudioFrame* buffer) override {} |
+ void ModifyBufferFloat(ChannelBuffer<float>* buffer) override {} |
+}; |
+ |
+// Linear fake recording device. The gain curve is a linear function mapping the |
+// mic levels range [0, 255] to [0.0, 1.0]. |
+class FakeRecordingDeviceLinear final : public FakeRecordingDeviceWorker { |
+ public: |
+ explicit FakeRecordingDeviceLinear(const int initial_mic_level) |
+ : FakeRecordingDeviceWorker(initial_mic_level) {} |
+ ~FakeRecordingDeviceLinear() override = default; |
+ void ModifyBufferInt16(AudioFrame* buffer) override { |
+ const size_t number_of_samples = |
+ buffer->samples_per_channel_ * buffer->num_channels_; |
+ RTC_DCHECK_LE(number_of_samples, AudioFrame::kMaxDataSizeSamples); |
+ int16_t* data = buffer->mutable_data(); |
+ for (size_t i = 0; i < number_of_samples; ++i) { |
+ const float sample_f = data[i]; |
+ if (undo_mic_level_ && *undo_mic_level_ > 0) { |
+ // Virtually restore the unmodified microphone level. |
+ data[i] = std::max(kInt16SampleMin, |
+ std::min(kInt16SampleMax, |
+ static_cast<int16_t>(sample_f * mic_level_ / |
+ *undo_mic_level_))); |
+ } else { |
+ // Simulate the mic gain only. |
+ data[i] = std::max( |
+ kInt16SampleMin, |
+ std::min(kInt16SampleMax, |
+ static_cast<int16_t>(sample_f * mic_level_ / 255.0f))); |
+ } |
+ } |
+ } |
+ void ModifyBufferFloat(ChannelBuffer<float>* buffer) override { |
+ for (size_t c = 0; c < buffer->num_channels(); ++c) { |
+ for (size_t i = 0; i < buffer->num_frames(); ++i) { |
+ if (undo_mic_level_ && *undo_mic_level_ > 0) { |
+ // Virtually restore the unmodified microphone level. |
+ buffer->channels()[c][i] = std::max( |
+ kFloatSampleMin, |
+ std::min(kFloatSampleMax, buffer->channels()[c][i] * mic_level_ / |
+ *undo_mic_level_)); |
+ } else { |
+ // Simulate the mic gain only. |
+ buffer->channels()[c][i] = |
+ std::max(kFloatSampleMin, |
+ std::min(kFloatSampleMax, buffer->channels()[c][i] * |
+ mic_level_ / 255.0f)); |
+ } |
+ } |
+ } |
+ } |
+}; |
+ |
+} // namespace |
+ |
+FakeRecordingDevice::FakeRecordingDevice(int initial_mic_level, |
+ int device_kind) { |
+ switch (device_kind) { |
+ case 0: |
+ worker_ = rtc::MakeUnique<FakeRecordingDeviceIdentity>(initial_mic_level); |
+ break; |
+ case 1: |
+ worker_ = rtc::MakeUnique<FakeRecordingDeviceLinear>(initial_mic_level); |
+ break; |
+ default: |
+ RTC_NOTREACHED(); |
+ break; |
+ } |
+} |
+ |
+FakeRecordingDevice::~FakeRecordingDevice() = default; |
+ |
+int FakeRecordingDevice::MicLevel() const { |
+ RTC_DCHECK(worker_); |
+ return worker_->mic_level(); |
+} |
+ |
+void FakeRecordingDevice::SetMicLevel(const int level) { |
+ RTC_DCHECK(worker_); |
+ if (level != worker_->mic_level()) |
+ LOG(LS_INFO) << "simulate mic level update: " << level; |
+ worker_->set_mic_level(level); |
+} |
+ |
+void FakeRecordingDevice::SetUndoMicLevel(const rtc::Optional<int> level) { |
+ RTC_DCHECK(worker_); |
+ // TODO(alessiob): The behavior with undo level equal to zero is not clear yet |
+ // and will be defined in future CLs once more FakeRecordingDeviceWorker |
+ // implementations need to be added. |
+ RTC_CHECK(!level || *level > 0) << "Zero undo mic level is unsupported"; |
+ worker_->set_undo_mic_level(level); |
+} |
+ |
+void FakeRecordingDevice::SimulateAnalogGain(AudioFrame* buffer) { |
+ RTC_DCHECK(worker_); |
+ worker_->ModifyBufferInt16(buffer); |
+} |
+ |
+void FakeRecordingDevice::SimulateAnalogGain(ChannelBuffer<float>* buffer) { |
+ RTC_DCHECK(worker_); |
+ worker_->ModifyBufferFloat(buffer); |
+} |
+ |
+} // namespace test |
+} // namespace webrtc |