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); | |
peah-webrtc
2017/09/15 09:36:20
Is this DCHECK really needed?
since both samples_p
AleBzk
2017/09/22 12:33:56
Done.
| |
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]; | |
peah-webrtc
2017/09/15 09:36:20
Why store data[i] in a local variable? It should b
peah-webrtc
2017/09/15 09:36:21
sample_f -> sample. No need to specify the type in
AleBzk
2017/09/22 12:33:55
Acknowledged.
AleBzk
2017/09/22 12:33:56
Done.
| |
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_); | |
peah-webrtc
2017/09/15 09:36:20
This should probably be a CHECK, since it is test
AleBzk
2017/09/22 12:33:56
Fixed this and all the other DCHECKs. Thanks.
| |
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; | |
peah-webrtc
2017/09/15 09:36:21
simulate -> Simulate
AleBzk
2017/09/22 12:33:55
Done.
| |
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_); | |
peah-webrtc
2017/09/15 09:36:20
This should probably be a CHECK, since it is test
AleBzk
2017/09/22 12:33:56
Done.
| |
156 worker_->ModifyBufferInt16(buffer); | |
157 } | |
158 | |
159 void FakeRecordingDevice::SimulateAnalogGain(ChannelBuffer<float>* buffer) { | |
160 RTC_DCHECK(worker_); | |
peah-webrtc
2017/09/15 09:36:21
This should probably be a CHECK, since it is test
AleBzk
2017/09/22 12:33:55
Done.
| |
161 worker_->ModifyBufferFloat(buffer); | |
162 } | |
163 | |
164 } // namespace test | |
165 } // namespace webrtc | |
OLD | NEW |