OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. |
| 3 * |
| 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ |
| 10 |
| 11 #include "webrtc/modules/audio_processing/test/fake_recording_device.h" |
| 12 |
| 13 #include <algorithm> |
| 14 |
| 15 #include "webrtc/rtc_base/logging.h" |
| 16 #include "webrtc/rtc_base/ptr_util.h" |
| 17 |
| 18 namespace webrtc { |
| 19 namespace test { |
| 20 |
| 21 namespace { |
| 22 |
| 23 constexpr int16_t kInt16SampleMin = -32768; |
| 24 constexpr int16_t kInt16SampleMax = 32767; |
| 25 constexpr float kFloatSampleMin = -32768.f; |
| 26 constexpr float kFloatSampleMax = 32767.0f; |
| 27 |
| 28 } // namespace |
| 29 |
| 30 // Abstract class for the different fake recording devices. |
| 31 class FakeRecordingDeviceWorker { |
| 32 public: |
| 33 explicit FakeRecordingDeviceWorker(const int initial_mic_level) |
| 34 : mic_level_(initial_mic_level) {} |
| 35 int mic_level() const { return mic_level_; } |
| 36 void set_mic_level(const int level) { mic_level_ = level; } |
| 37 void set_undo_mic_level(const rtc::Optional<int> level) { |
| 38 undo_mic_level_ = level; |
| 39 } |
| 40 virtual ~FakeRecordingDeviceWorker() = default; |
| 41 virtual void ModifyBufferInt16(AudioFrame* buffer) = 0; |
| 42 virtual void ModifyBufferFloat(ChannelBuffer<float>* buffer) = 0; |
| 43 |
| 44 protected: |
| 45 // Mic level to simulate. |
| 46 int mic_level_; |
| 47 // Optional mic level to undo. |
| 48 rtc::Optional<int> undo_mic_level_; |
| 49 }; |
| 50 |
| 51 namespace { |
| 52 |
| 53 // Identity fake recording device. The samples are not modified, which is |
| 54 // equivalent to a constant gain curve at 1.0 - only used for testing. |
| 55 class FakeRecordingDeviceIdentity final : public FakeRecordingDeviceWorker { |
| 56 public: |
| 57 explicit FakeRecordingDeviceIdentity(const int initial_mic_level) |
| 58 : FakeRecordingDeviceWorker(initial_mic_level) {} |
| 59 ~FakeRecordingDeviceIdentity() override = default; |
| 60 void ModifyBufferInt16(AudioFrame* buffer) override {} |
| 61 void ModifyBufferFloat(ChannelBuffer<float>* buffer) override {} |
| 62 }; |
| 63 |
| 64 // Linear fake recording device. The gain curve is a linear function mapping the |
| 65 // mic levels range [0, 255] to [0.0, 1.0]. |
| 66 class FakeRecordingDeviceLinear final : public FakeRecordingDeviceWorker { |
| 67 public: |
| 68 explicit FakeRecordingDeviceLinear(const int initial_mic_level) |
| 69 : FakeRecordingDeviceWorker(initial_mic_level) {} |
| 70 ~FakeRecordingDeviceLinear() override = default; |
| 71 void ModifyBufferInt16(AudioFrame* buffer) override { |
| 72 const size_t number_of_samples = |
| 73 buffer->samples_per_channel_ * buffer->num_channels_; |
| 74 RTC_DCHECK_LE(number_of_samples, AudioFrame::kMaxDataSizeSamples); |
| 75 int16_t* data = buffer->mutable_data(); |
| 76 for (size_t i = 0; i < number_of_samples; ++i) { |
| 77 const float sample_f = data[i]; |
| 78 if (undo_mic_level_ && *undo_mic_level_ > 0) { |
| 79 // Virtually restore the unmodified microphone level. |
| 80 data[i] = std::max(kInt16SampleMin, |
| 81 std::min(kInt16SampleMax, |
| 82 static_cast<int16_t>(sample_f * mic_level_ / |
| 83 *undo_mic_level_))); |
| 84 } else { |
| 85 // Simulate the mic gain only. |
| 86 data[i] = std::max( |
| 87 kInt16SampleMin, |
| 88 std::min(kInt16SampleMax, |
| 89 static_cast<int16_t>(sample_f * mic_level_ / 255.0f))); |
| 90 } |
| 91 } |
| 92 } |
| 93 void ModifyBufferFloat(ChannelBuffer<float>* buffer) override { |
| 94 for (size_t c = 0; c < buffer->num_channels(); ++c) { |
| 95 for (size_t i = 0; i < buffer->num_frames(); ++i) { |
| 96 if (undo_mic_level_ && *undo_mic_level_ > 0) { |
| 97 // Virtually restore the unmodified microphone level. |
| 98 buffer->channels()[c][i] = std::max( |
| 99 kFloatSampleMin, |
| 100 std::min(kFloatSampleMax, buffer->channels()[c][i] * mic_level_ / |
| 101 *undo_mic_level_)); |
| 102 } else { |
| 103 // Simulate the mic gain only. |
| 104 buffer->channels()[c][i] = |
| 105 std::max(kFloatSampleMin, |
| 106 std::min(kFloatSampleMax, buffer->channels()[c][i] * |
| 107 mic_level_ / 255.0f)); |
| 108 } |
| 109 } |
| 110 } |
| 111 } |
| 112 }; |
| 113 |
| 114 } // namespace |
| 115 |
| 116 FakeRecordingDevice::FakeRecordingDevice(int initial_mic_level, |
| 117 int device_kind) { |
| 118 switch (device_kind) { |
| 119 case 0: |
| 120 worker_ = rtc::MakeUnique<FakeRecordingDeviceIdentity>(initial_mic_level); |
| 121 break; |
| 122 case 1: |
| 123 worker_ = rtc::MakeUnique<FakeRecordingDeviceLinear>(initial_mic_level); |
| 124 break; |
| 125 default: |
| 126 RTC_NOTREACHED(); |
| 127 break; |
| 128 } |
| 129 } |
| 130 |
| 131 FakeRecordingDevice::~FakeRecordingDevice() = default; |
| 132 |
| 133 int FakeRecordingDevice::MicLevel() const { |
| 134 RTC_DCHECK(worker_); |
| 135 return worker_->mic_level(); |
| 136 } |
| 137 |
| 138 void FakeRecordingDevice::SetMicLevel(const int level) { |
| 139 RTC_DCHECK(worker_); |
| 140 if (level != worker_->mic_level()) |
| 141 LOG(LS_INFO) << "simulate mic level update: " << level; |
| 142 worker_->set_mic_level(level); |
| 143 } |
| 144 |
| 145 void FakeRecordingDevice::SetUndoMicLevel(const rtc::Optional<int> level) { |
| 146 RTC_DCHECK(worker_); |
| 147 // TODO(alessiob): The behavior with undo level equal to zero is not clear yet |
| 148 // and will be defined in future CLs once more FakeRecordingDeviceWorker |
| 149 // implementations need to be added. |
| 150 RTC_CHECK(!level || *level > 0) << "Zero undo mic level is unsupported"; |
| 151 worker_->set_undo_mic_level(level); |
| 152 } |
| 153 |
| 154 void FakeRecordingDevice::SimulateAnalogGain(AudioFrame* buffer) { |
| 155 RTC_DCHECK(worker_); |
| 156 worker_->ModifyBufferInt16(buffer); |
| 157 } |
| 158 |
| 159 void FakeRecordingDevice::SimulateAnalogGain(ChannelBuffer<float>* buffer) { |
| 160 RTC_DCHECK(worker_); |
| 161 worker_->ModifyBufferFloat(buffer); |
| 162 } |
| 163 |
| 164 } // namespace test |
| 165 } // namespace webrtc |
OLD | NEW |