OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/modules/audio_mixer/frame_combiner.h" | 11 #include "webrtc/modules/audio_mixer/frame_combiner.h" |
12 | 12 |
13 #include <numeric> | 13 #include <numeric> |
14 #include <sstream> | 14 #include <sstream> |
15 #include <string> | 15 #include <string> |
16 | 16 |
17 #include "webrtc/audio/utility/audio_frame_operations.h" | |
17 #include "webrtc/base/checks.h" | 18 #include "webrtc/base/checks.h" |
19 #include "webrtc/modules/audio_mixer/frame_combiner_test_tools.h" | |
18 #include "webrtc/test/gtest.h" | 20 #include "webrtc/test/gtest.h" |
19 | 21 |
20 namespace webrtc { | 22 namespace webrtc { |
21 | 23 |
22 namespace { | 24 namespace { |
23 std::string ProduceDebugText(int sample_rate_hz, | 25 std::string ProduceDebugText(int sample_rate_hz, |
24 int number_of_channels, | 26 int number_of_channels, |
25 int number_of_sources) { | 27 int number_of_sources) { |
26 std::ostringstream ss; | 28 std::ostringstream ss; |
27 ss << "Sample rate: " << sample_rate_hz << " "; | 29 ss << "Sample rate: " << sample_rate_hz << " ,"; |
28 ss << "Number of channels: " << number_of_channels << " "; | 30 ss << "number of channels: " << number_of_channels << " ,"; |
29 ss << "Number of sources: " << number_of_sources; | 31 ss << "number of sources: " << number_of_sources; |
30 return ss.str(); | 32 return ss.str(); |
31 } | 33 } |
32 | 34 |
35 std::string ProduceDebugText(int sample_rate_hz, | |
36 int number_of_channels, | |
37 int number_of_sources, | |
38 bool limiter_active, | |
39 float wave_frequency) { | |
40 std::ostringstream ss; | |
41 ss << "Sample rate: " << sample_rate_hz << " ,"; | |
42 ss << "number of channels: " << number_of_channels << " ,"; | |
43 ss << "number of sources: " << number_of_sources << " ,"; | |
44 ss << "limiter active: " << limiter_active << " ,"; | |
45 ss << "wave frequency: " << wave_frequency << " ,"; | |
46 return ss.str(); | |
47 } | |
48 | |
33 AudioFrame frame1; | 49 AudioFrame frame1; |
34 AudioFrame frame2; | 50 AudioFrame frame2; |
35 AudioFrame audio_frame_for_mixing; | 51 AudioFrame audio_frame_for_mixing; |
36 | 52 |
37 void SetUpFrames(int sample_rate_hz, int number_of_channels) { | 53 void SetUpFrames(int sample_rate_hz, int number_of_channels) { |
38 for (auto* frame : {&frame1, &frame2}) { | 54 for (auto* frame : {&frame1, &frame2}) { |
39 frame->UpdateFrame(-1, 0, nullptr, | 55 frame->UpdateFrame(-1, 0, nullptr, |
40 rtc::CheckedDivExact(sample_rate_hz, 100), | 56 rtc::CheckedDivExact(sample_rate_hz, 100), |
41 sample_rate_hz, AudioFrame::kNormalSpeech, | 57 sample_rate_hz, AudioFrame::kNormalSpeech, |
42 AudioFrame::kVadActive, number_of_channels); | 58 AudioFrame::kVadActive, number_of_channels); |
43 } | 59 } |
44 } | 60 } |
45 } // namespace | 61 } // namespace |
46 | 62 |
47 TEST(FrameCombiner, BasicApiCallsLimiter) { | 63 TEST(FrameCombiner, BasicApiCallsLimiter) { |
48 FrameCombiner combiner(true); | 64 FrameCombiner combiner(true); |
49 for (const int rate : {8000, 16000, 32000, 48000}) { | 65 for (const int rate : {8000, 16000, 32000, 48000}) { |
50 for (const int number_of_channels : {1, 2}) { | 66 for (const int number_of_channels : {1, 2}) { |
51 const std::vector<AudioFrame*> all_frames = {&frame1, &frame2}; | 67 const std::vector<AudioFrame*> all_frames = {&frame1, &frame2}; |
52 SetUpFrames(rate, number_of_channels); | 68 SetUpFrames(rate, number_of_channels); |
53 | 69 |
54 for (const int number_of_frames : {0, 1, 2}) { | 70 for (const int number_of_frames : {0, 1, 2}) { |
55 SCOPED_TRACE( | 71 SCOPED_TRACE( |
56 ProduceDebugText(rate, number_of_channels, number_of_frames)); | 72 ProduceDebugText(rate, number_of_channels, number_of_frames)); |
57 const std::vector<AudioFrame*> frames_to_combine( | 73 const std::vector<AudioFrame*> frames_to_combine( |
58 all_frames.begin(), all_frames.begin() + number_of_frames); | 74 all_frames.begin(), all_frames.begin() + number_of_frames); |
59 combiner.Combine(frames_to_combine, number_of_channels, rate, | 75 combiner.Combine(frames_to_combine, number_of_channels, rate, |
60 &audio_frame_for_mixing); | 76 frames_to_combine.size(), &audio_frame_for_mixing); |
61 } | 77 } |
62 } | 78 } |
63 } | 79 } |
64 } | 80 } |
65 | 81 |
66 // No APM limiter means no AudioProcessing::NativeRate restriction | 82 // No APM limiter means no AudioProcessing::NativeRate restriction |
67 // on rate. The rate has to be divisible by 100 since we use | 83 // on rate. The rate has to be divisible by 100 since we use |
68 // 10 ms frames, though. | 84 // 10 ms frames, though. |
69 TEST(FrameCombiner, BasicApiCallsNoLimiter) { | 85 TEST(FrameCombiner, BasicApiCallsNoLimiter) { |
70 FrameCombiner combiner(false); | 86 FrameCombiner combiner(false); |
71 for (const int rate : {8000, 10000, 11000, 32000, 44100}) { | 87 for (const int rate : {8000, 10000, 11000, 32000, 44100}) { |
72 for (const int number_of_channels : {1, 2}) { | 88 for (const int number_of_channels : {1, 2}) { |
73 const std::vector<AudioFrame*> all_frames = {&frame1, &frame2}; | 89 const std::vector<AudioFrame*> all_frames = {&frame1, &frame2}; |
74 SetUpFrames(rate, number_of_channels); | 90 SetUpFrames(rate, number_of_channels); |
75 | 91 |
76 for (const int number_of_frames : {0, 1, 2}) { | 92 for (const int number_of_frames : {0, 1, 2}) { |
77 SCOPED_TRACE( | 93 SCOPED_TRACE( |
78 ProduceDebugText(rate, number_of_channels, number_of_frames)); | 94 ProduceDebugText(rate, number_of_channels, number_of_frames)); |
79 const std::vector<AudioFrame*> frames_to_combine( | 95 const std::vector<AudioFrame*> frames_to_combine( |
80 all_frames.begin(), all_frames.begin() + number_of_frames); | 96 all_frames.begin(), all_frames.begin() + number_of_frames); |
81 combiner.Combine(frames_to_combine, number_of_channels, rate, | 97 combiner.Combine(frames_to_combine, number_of_channels, rate, |
82 &audio_frame_for_mixing); | 98 frames_to_combine.size(), &audio_frame_for_mixing); |
83 } | 99 } |
84 } | 100 } |
85 } | 101 } |
86 } | 102 } |
87 | 103 |
88 TEST(FrameCombiner, CombiningZeroFramesShouldProduceSilence) { | 104 TEST(FrameCombiner, CombiningZeroFramesShouldProduceSilence) { |
89 FrameCombiner combiner(false); | 105 FrameCombiner combiner(false); |
90 for (const int rate : {8000, 10000, 11000, 32000, 44100}) { | 106 for (const int rate : {8000, 10000, 11000, 32000, 44100}) { |
91 for (const int number_of_channels : {1, 2}) { | 107 for (const int number_of_channels : {1, 2}) { |
92 SCOPED_TRACE(ProduceDebugText(rate, number_of_channels, 0)); | 108 SCOPED_TRACE(ProduceDebugText(rate, number_of_channels, 0)); |
93 | 109 |
94 const std::vector<AudioFrame*> frames_to_combine; | 110 const std::vector<AudioFrame*> frames_to_combine; |
95 combiner.Combine(frames_to_combine, number_of_channels, rate, | 111 combiner.Combine(frames_to_combine, number_of_channels, rate, |
96 &audio_frame_for_mixing); | 112 frames_to_combine.size(), &audio_frame_for_mixing); |
97 | 113 |
98 const std::vector<int16_t> mixed_data( | 114 const std::vector<int16_t> mixed_data( |
99 audio_frame_for_mixing.data_, | 115 audio_frame_for_mixing.data_, |
100 audio_frame_for_mixing.data_ + number_of_channels * rate / 100); | 116 audio_frame_for_mixing.data_ + number_of_channels * rate / 100); |
101 | 117 |
102 const std::vector<int16_t> expected(number_of_channels * rate / 100, 0); | 118 const std::vector<int16_t> expected(number_of_channels * rate / 100, 0); |
103 EXPECT_EQ(mixed_data, expected); | 119 EXPECT_EQ(mixed_data, expected); |
104 } | 120 } |
105 } | 121 } |
106 } | 122 } |
107 | 123 |
108 TEST(FrameCombiner, CombiningOneFrameShouldNotChangeFrame) { | 124 TEST(FrameCombiner, CombiningOneFrameShouldNotChangeFrame) { |
109 FrameCombiner combiner(false); | 125 FrameCombiner combiner(false); |
110 for (const int rate : {8000, 10000, 11000, 32000, 44100}) { | 126 for (const int rate : {8000, 10000, 11000, 32000, 44100}) { |
111 for (const int number_of_channels : {1, 2}) { | 127 for (const int number_of_channels : {1, 2}) { |
112 SCOPED_TRACE(ProduceDebugText(rate, number_of_channels, 1)); | 128 SCOPED_TRACE(ProduceDebugText(rate, number_of_channels, 1)); |
113 | 129 |
114 SetUpFrames(rate, number_of_channels); | 130 SetUpFrames(rate, number_of_channels); |
115 std::iota(frame1.data_, frame1.data_ + number_of_channels * rate / 100, | 131 std::iota(frame1.data_, frame1.data_ + number_of_channels * rate / 100, |
116 0); | 132 0); |
117 const std::vector<AudioFrame*> frames_to_combine = {&frame1}; | 133 const std::vector<AudioFrame*> frames_to_combine = {&frame1}; |
118 combiner.Combine(frames_to_combine, number_of_channels, rate, | 134 combiner.Combine(frames_to_combine, number_of_channels, rate, |
119 &audio_frame_for_mixing); | 135 frames_to_combine.size(), &audio_frame_for_mixing); |
120 | 136 |
121 const std::vector<int16_t> mixed_data( | 137 const std::vector<int16_t> mixed_data( |
122 audio_frame_for_mixing.data_, | 138 audio_frame_for_mixing.data_, |
123 audio_frame_for_mixing.data_ + number_of_channels * rate / 100); | 139 audio_frame_for_mixing.data_ + number_of_channels * rate / 100); |
124 | 140 |
125 std::vector<int16_t> expected(number_of_channels * rate / 100); | 141 std::vector<int16_t> expected(number_of_channels * rate / 100); |
126 std::iota(expected.begin(), expected.end(), 0); | 142 std::iota(expected.begin(), expected.end(), 0); |
127 EXPECT_EQ(mixed_data, expected); | 143 EXPECT_EQ(mixed_data, expected); |
128 } | 144 } |
129 } | 145 } |
130 } | 146 } |
131 | 147 |
148 // Send a sine curve through the FrameCombiner, and check that the | |
149 // difference between input and output varies smoothly. This is to | |
150 // catch issues like chromium:695993. | |
151 TEST(FrameCombiner, GainCurveIsSmoothForAlternatingNumberOfStreams) { | |
152 // Test doesn't work with rates requiring a band split, because it | |
153 // introduces a small delay measured in single samples, and this | |
154 // test cannot handle it. | |
155 // | |
156 // TODO(aleloi): Add more rates when APM limiter doesn't use band | |
157 // split. | |
158 for (const bool use_limiter : {true, false}) { | |
159 for (const int rate : {8000, 16000}) { | |
160 for (const int number_of_channels : {1, 2}) { | |
161 for (const float wave_frequency : | |
162 {50, 100, 200, 400, 800, 1600, 3200}) { | |
ivoc
2017/03/28 16:11:06
I don't think it's really necessary to test every
| |
163 SCOPED_TRACE(ProduceDebugText(rate, number_of_channels, 1, | |
164 use_limiter, wave_frequency)); | |
165 | |
166 FrameCombiner combiner(use_limiter); | |
167 | |
168 constexpr int16_t wave_amplitude = 30000; | |
169 SineWaveGenerator wave_generator(wave_frequency, wave_amplitude); | |
170 | |
171 GainChangeCalculator change_calculator; | |
172 float cumulative_change = 0.f; | |
173 | |
174 constexpr int16_t iterations = 100; | |
175 | |
176 for (int i = 0; i < iterations; ++i) { | |
177 SetUpFrames(rate, number_of_channels); | |
178 wave_generator.GenerateNextFrame(&frame1); | |
179 AudioFrameOperations::Mute(&frame2); | |
180 | |
181 std::vector<AudioFrame*> frames_to_combine = {&frame1}; | |
182 if (i % 2 == 0) { | |
183 frames_to_combine.push_back(&frame2); | |
184 } | |
185 const size_t number_of_samples = | |
186 frame1.samples_per_channel_ * number_of_channels; | |
187 | |
188 // Ensures limiter is on if 'use_limiter'. | |
189 const size_t number_of_streams = 2; | |
190 combiner.Combine(frames_to_combine, number_of_channels, rate, | |
191 number_of_streams, &audio_frame_for_mixing); | |
192 cumulative_change += change_calculator.CalculateGainChange( | |
193 rtc::ArrayView<const int16_t>(frame1.data_, number_of_samples), | |
194 rtc::ArrayView<const int16_t>(audio_frame_for_mixing.data_, | |
195 number_of_samples)); | |
196 } | |
197 RTC_DCHECK_LT(cumulative_change, 10); | |
198 } | |
199 } | |
200 } | |
201 } | |
202 } | |
132 } // namespace webrtc | 203 } // namespace webrtc |
OLD | NEW |