Chromium Code Reviews| 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; | 
| 
 
AleBzk
2017/08/18 07:49:46
The range was wrong.
 
 | 
| + | 
| +} // 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); | 
| +} | 
| 
 
AleBzk
2017/08/18 07:49:46
As discussed offline with Per, FakeRecordingDevice
 
 | 
| + | 
| +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 |