OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2012 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 <cmath> | |
12 #include <cstdio> | |
13 | |
14 #include <algorithm> | |
15 | |
16 #include "gflags/gflags.h" | |
17 #include "testing/gtest/include/gtest/gtest.h" | |
18 #include "webrtc/modules/audio_processing/agc/agc.h" | |
19 #include "webrtc/modules/audio_processing/agc/utility.h" | |
20 #include "webrtc/modules/audio_processing/include/audio_processing.h" | |
21 #include "webrtc/modules/interface/module_common_types.h" | |
22 #include "webrtc/system_wrappers/interface/logging.h" | |
23 #include "webrtc/test/testsupport/trace_to_stderr.h" | |
24 #include "webrtc/tools/agc/agc_manager.h" | |
25 #include "webrtc/tools/agc/test_utils.h" | |
26 #include "webrtc/voice_engine/mock/fake_voe_external_media.h" | |
27 #include "webrtc/voice_engine/mock/mock_voe_volume_control.h" | |
28 | |
29 DEFINE_string(in, "in.pcm", "input filename"); | |
30 DEFINE_string(out, "out.pcm", "output filename"); | |
31 DEFINE_int32(rate, 16000, "sample rate in Hz"); | |
32 DEFINE_int32(channels, 1, "number of channels"); | |
33 DEFINE_int32(level, -18, "target level in RMS dBFs [-100, 0]"); | |
34 DEFINE_bool(limiter, true, "enable a limiter for the compression stage"); | |
35 DEFINE_int32(cmp_level, 2, "target level in dBFs for the compression stage"); | |
36 DEFINE_int32(mic_gain, 80, "range of gain provided by the virtual mic in dB"); | |
37 DEFINE_int32(gain_offset, 0, | |
38 "an amount (in dB) to add to every entry in the gain map"); | |
39 DEFINE_string(gain_file, "", | |
40 "filename providing a mic gain mapping. The file should be text containing " | |
41 "a (floating-point) gain entry in dBFs per line corresponding to levels " | |
42 "from 0 to 255."); | |
43 | |
44 using ::testing::_; | |
45 using ::testing::ByRef; | |
46 using ::testing::DoAll; | |
47 using ::testing::Mock; | |
48 using ::testing::Return; | |
49 using ::testing::SaveArg; | |
50 using ::testing::SetArgReferee; | |
51 | |
52 namespace webrtc { | |
53 namespace { | |
54 | |
55 const char kUsage[] = "\nProcess an audio file to simulate an analog agc."; | |
56 | |
57 void ReadGainMapFromFile(FILE* file, int offset, int gain_map[256]) { | |
58 for (int i = 0; i < 256; ++i) { | |
59 float gain = 0; | |
60 ASSERT_EQ(1, fscanf(file, "%f", &gain)); | |
61 gain_map[i] = std::floor(gain + 0.5); | |
62 } | |
63 | |
64 // Adjust from dBFs to gain in dB. We assume that level 127 provides 0 dB | |
65 // gain. This corresponds to the interpretation in MicLevel2Gain(). | |
66 const int midpoint = gain_map[127]; | |
67 printf("Gain map\n"); | |
68 for (int i = 0; i < 256; ++i) { | |
69 gain_map[i] += offset - midpoint; | |
70 if (i % 5 == 0) { | |
71 printf("%d: %d dB\n", i, gain_map[i]); | |
72 } | |
73 } | |
74 } | |
75 | |
76 void CalculateGainMap(int gain_range_db, int offset, int gain_map[256]) { | |
77 printf("Gain map\n"); | |
78 for (int i = 0; i < 256; ++i) { | |
79 gain_map[i] = std::floor(MicLevel2Gain(gain_range_db, i) + 0.5) + offset; | |
80 if (i % 5 == 0) { | |
81 printf("%d: %d dB\n", i, gain_map[i]); | |
82 } | |
83 } | |
84 } | |
85 | |
86 void RunAgc() { | |
87 test::TraceToStderr trace_to_stderr(true); | |
88 FILE* in_file = fopen(FLAGS_in.c_str(), "rb"); | |
89 ASSERT_TRUE(in_file != NULL); | |
90 FILE* out_file = fopen(FLAGS_out.c_str(), "wb"); | |
91 ASSERT_TRUE(out_file != NULL); | |
92 | |
93 int gain_map[256]; | |
94 if (!FLAGS_gain_file.empty()) { | |
95 FILE* gain_file = fopen(FLAGS_gain_file.c_str(), "rt"); | |
96 ASSERT_TRUE(gain_file != NULL); | |
97 ReadGainMapFromFile(gain_file, FLAGS_gain_offset, gain_map); | |
98 fclose(gain_file); | |
99 } else { | |
100 CalculateGainMap(FLAGS_mic_gain, FLAGS_gain_offset, gain_map); | |
101 } | |
102 | |
103 FakeVoEExternalMedia media; | |
104 MockVoEVolumeControl volume; | |
105 Agc* agc = new Agc; | |
106 AudioProcessing* audioproc = AudioProcessing::Create(); | |
107 ASSERT_TRUE(audioproc != NULL); | |
108 AgcManager manager(&media, &volume, agc, audioproc); | |
109 | |
110 int mic_level = 128; | |
111 int last_mic_level = mic_level; | |
112 EXPECT_CALL(volume, GetMicVolume(_)) | |
113 .WillRepeatedly(DoAll(SetArgReferee<0>(ByRef(mic_level)), Return(0))); | |
114 EXPECT_CALL(volume, SetMicVolume(_)) | |
115 .WillRepeatedly(DoAll(SaveArg<0>(&mic_level), Return(0))); | |
116 | |
117 manager.Enable(true); | |
118 ASSERT_EQ(0, agc->set_target_level_dbfs(FLAGS_level)); | |
119 const AudioProcessing::Error kNoErr = AudioProcessing::kNoError; | |
120 GainControl* gctrl = audioproc->gain_control(); | |
121 ASSERT_EQ(kNoErr, gctrl->set_target_level_dbfs(FLAGS_cmp_level)); | |
122 ASSERT_EQ(kNoErr, gctrl->enable_limiter(FLAGS_limiter)); | |
123 | |
124 AudioFrame frame; | |
125 frame.num_channels_ = FLAGS_channels; | |
126 frame.sample_rate_hz_ = FLAGS_rate; | |
127 frame.samples_per_channel_ = FLAGS_rate / 100; | |
128 const size_t frame_length = frame.samples_per_channel_ * FLAGS_channels; | |
129 size_t sample_count = 0; | |
130 while (fread(frame.data_, sizeof(int16_t), frame_length, in_file) == | |
131 frame_length) { | |
132 SimulateMic(gain_map, mic_level, last_mic_level, &frame); | |
133 last_mic_level = mic_level; | |
134 media.CallProcess(kRecordingAllChannelsMixed, frame.data_, | |
135 frame.samples_per_channel_, FLAGS_rate, FLAGS_channels); | |
136 ASSERT_EQ(frame_length, | |
137 fwrite(frame.data_, sizeof(int16_t), frame_length, out_file)); | |
138 sample_count += frame_length; | |
139 trace_to_stderr.SetTimeSeconds(static_cast<float>(sample_count) / | |
140 FLAGS_channels / FLAGS_rate); | |
141 } | |
142 fclose(in_file); | |
143 fclose(out_file); | |
144 EXPECT_CALL(volume, Release()); | |
145 } | |
146 | |
147 } // namespace | |
148 } // namespace webrtc | |
149 | |
150 int main(int argc, char* argv[]) { | |
151 google::SetUsageMessage(webrtc::kUsage); | |
152 google::ParseCommandLineFlags(&argc, &argv, true); | |
153 webrtc::RunAgc(); | |
154 return 0; | |
155 } | |
OLD | NEW |