Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(429)

Side by Side Diff: chromecast/media/cma/backend/alsa/slew_volume_unittests.cc

Issue 2860673003: [Chromecast] Correct libcast_governor behavior. (Closed)
Patch Set: address halliwell@'s comments Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <cmath>
6 #include <cstdint>
7 #include <limits>
8 #include <vector>
9
10 #include "base/logging.h"
11 #include "base/macros.h"
12 #include "base/memory/ptr_util.h"
13 #include "chromecast/media/cma/backend/alsa/slew_volume.h"
14 #include "media/base/audio_bus.h"
15 #include "media/base/vector_math.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace chromecast {
19 namespace media {
20
21 namespace {
22
23 const int kNumChannels = 2;
24 const int kNumFrames = 100;
25 const float kSinFrequency = 1.0f / kNumFrames;
26 const int kBytesPerSample = sizeof(int32_t);
27
28 // Frequency is in frames (frequency = frequency_in_hz / sample rate)
29 std::unique_ptr<::media::AudioBus> GetSineData(size_t frames, float frequency) {
30 auto data = ::media::AudioBus::Create(kNumChannels, frames);
31 std::vector<int32_t> sine(frames * 2);
32 for (size_t i = 0; i < frames; ++i) {
33 // Offset by 1 because sin(0) = 0 and the first value is a special case.
34 sine[i * 2] = sin(static_cast<float>(i + 1) * frequency * 2 * M_PI) *
35 std::numeric_limits<int32_t>::max();
36 sine[i * 2 + 1] = cos(static_cast<float>(i + 1) * frequency * 2 * M_PI) *
37 std::numeric_limits<int32_t>::max();
38 }
39 data->FromInterleaved(sine.data(), frames, kBytesPerSample);
40 return data;
41 }
42
43 // Gets pointers to the data in an audiobus.
44 // If |swapped| is true, the channel order will be swapped.
45 std::vector<float*> GetDataChannels(::media::AudioBus* audio,
46 bool swapped = false) {
47 std::vector<float*> data(kNumChannels);
48 for (int i = 0; i < kNumChannels; ++i) {
49 int source_channel = swapped ? (i + 1) % kNumChannels : i;
50 data[i] = audio->channel(source_channel);
51 }
52 return data;
53 }
54
55 void ScaleData(const std::vector<float*>& data, int frames, float scale) {
56 for (size_t ch = 0; ch < data.size(); ++ch) {
57 for (int f = 0; f < frames; ++f) {
58 data[ch][f] *= scale;
59 }
60 }
61 }
62
63 void CompareDataPartial(const std::vector<float*>& expected,
64 const std::vector<float*>& actual,
65 int start,
66 int end) {
67 ASSERT_GE(start, 0);
68 ASSERT_LT(start, end);
69 ASSERT_EQ(expected.size(), actual.size());
70
71 for (size_t ch = 0; ch < expected.size(); ++ch) {
72 for (int f = start; f < end; ++f) {
73 EXPECT_FLOAT_EQ(expected[ch][f], actual[ch][f])
74 << "ch: " << ch << " f: " << f;
75 }
76 }
77 }
78
79 } // namespace
80
81 class SlewVolumeBaseTest : public ::testing::Test {
82 protected:
83 SlewVolumeBaseTest() = default;
84 ~SlewVolumeBaseTest() override = default;
85
86 void SetUp() override {
87 slew_volume_ = base::MakeUnique<SlewVolume>();
88 slew_volume_->Interrupted();
89 MakeData(kNumFrames);
90 }
91
92 void MakeData(int num_frames) {
93 num_frames_ = num_frames;
94 data_bus_ = GetSineData(num_frames_, kSinFrequency);
95 data_bus_2_ = GetSineData(num_frames_, kSinFrequency);
96 expected_bus_ = GetSineData(num_frames_, kSinFrequency);
97 data_ = GetDataChannels(data_bus_.get());
98 data_2_ = GetDataChannels(data_bus_2_.get(), true /* swapped */);
99 expected_ = GetDataChannels(expected_bus_.get());
100 }
101
102 void CompareBuffers(int start = 0, int end = -1) {
103 if (end == -1) {
104 end = num_frames_;
105 }
106
107 ASSERT_GE(start, 0);
108 ASSERT_LT(start, end);
109 ASSERT_LE(end, num_frames_);
110
111 CompareDataPartial(expected_, data_, start, end);
112 }
113
114 void ClearInterrupted() {
115 float throwaway __attribute__((__aligned__(16))) = 0.0f;
116 slew_volume_->ProcessFMUL(false, &throwaway, 1, &throwaway);
117 }
118
119 int num_frames_;
120
121 std::unique_ptr<SlewVolume> slew_volume_;
122 std::unique_ptr<::media::AudioBus> data_bus_;
123 std::unique_ptr<::media::AudioBus> data_bus_2_;
124 std::unique_ptr<::media::AudioBus> expected_bus_;
125 std::vector<float*> data_;
126 std::vector<float*> data_2_;
127 std::vector<float*> expected_;
128
129 private:
130 DISALLOW_COPY_AND_ASSIGN(SlewVolumeBaseTest);
131 };
132
133 TEST_F(SlewVolumeBaseTest, BadSampleRate) {
134 ASSERT_DEATH(slew_volume_->SetSampleRate(0), "sample_rate");
135 }
136
137 TEST_F(SlewVolumeBaseTest, BadSlewTime) {
138 ASSERT_DEATH(slew_volume_->SetMaxSlewTimeMs(-1), "");
139 }
140
141 class SlewVolumeSteadyStateTest : public SlewVolumeBaseTest {
142 protected:
143 SlewVolumeSteadyStateTest() = default;
144 ~SlewVolumeSteadyStateTest() override = default;
145
146 void SetUp() override {
147 SlewVolumeBaseTest::SetUp();
148 slew_volume_->Interrupted();
149 }
150
151 private:
152 DISALLOW_COPY_AND_ASSIGN(SlewVolumeSteadyStateTest);
153 };
154
155 TEST_F(SlewVolumeSteadyStateTest, FMULNoOp) {
156 slew_volume_->SetVolume(1.0f);
157
158 slew_volume_->ProcessFMUL(false /* repeat transition */, data_[0],
159 num_frames_, data_[0]);
160 slew_volume_->ProcessFMUL(true /* repeat transition */, data_[1], num_frames_,
161 data_[1]);
162 CompareBuffers();
163 }
164
165 TEST_F(SlewVolumeSteadyStateTest, FMULCopy) {
166 slew_volume_->SetVolume(1.0f);
167
168 slew_volume_->ProcessFMUL(false /* repeat transition */, data_2_[0],
169 num_frames_, data_[0]);
170 slew_volume_->ProcessFMUL(true /* repeat transition */, data_2_[1],
171 num_frames_, data_[1]);
172 CompareDataPartial(data_2_, data_, 0, num_frames_);
173 }
174
175 TEST_F(SlewVolumeSteadyStateTest, FMULZero) {
176 slew_volume_->SetVolume(0.0f);
177 slew_volume_->ProcessFMUL(false, /* repeat transition */
178 data_[0], num_frames_, data_[0]);
179 slew_volume_->ProcessFMUL(true /* repeat transition */, data_[1], num_frames_,
180 data_[1]);
181
182 for (size_t ch = 0; ch < data_.size(); ++ch) {
183 for (int f = 0; f < num_frames_; ++f) {
184 EXPECT_EQ(0.0f, data_[ch][f]) << "at ch " << ch << "frame " << f;
185 }
186 }
187 }
188
189 TEST_F(SlewVolumeSteadyStateTest, FMULInterrupted) {
190 float volume = 0.6f;
191 slew_volume_->SetVolume(volume);
192
193 slew_volume_->ProcessFMUL(false /* repeat transition */,
194 data_[0] /* source */, num_frames_,
195 data_[0] /* dst */);
196 slew_volume_->ProcessFMUL(true /* repeat transition */, data_[1] /* source */,
197 num_frames_, data_[1] /* dst */);
198 ScaleData(expected_, num_frames_, volume);
199 CompareBuffers();
200 }
201
202 TEST_F(SlewVolumeSteadyStateTest, FMACNoOp) {
203 slew_volume_->SetVolume(0.0f);
204 slew_volume_->ProcessFMAC(false /* repeat transition */,
205 data_2_[0] /* source */, num_frames_,
206 data_[0] /* dst */);
207 slew_volume_->ProcessFMAC(false /* repeat transition */,
208 data_2_[1] /* source */, num_frames_,
209 data_[1] /*dst */);
210 CompareBuffers();
211 }
212
213 class SlewVolumeDynamicTest
214 : public SlewVolumeBaseTest,
215 public ::testing::WithParamInterface<std::tuple<int, int>> {
216 protected:
217 SlewVolumeDynamicTest() = default;
218 ~SlewVolumeDynamicTest() override = default;
219
220 void SetUp() override {
221 SlewVolumeBaseTest::SetUp();
222 sample_rate_ = std::get<0>(GetParam());
223 slew_time_ms_ = std::get<1>(GetParam());
224 slew_time_frames_ = sample_rate_ * slew_time_ms_ / 1000;
225 slew_volume_->SetSampleRate(sample_rate_);
226 slew_volume_->SetMaxSlewTimeMs(slew_time_ms_);
227
228 int num_frames = slew_time_frames_ + 2; // +2 frames for numeric errors.
229 ASSERT_GE(num_frames, 1);
230 MakeData(num_frames);
231 }
232
233 // Checks data_ = slew_volume_(expected_)
234 void CheckSlewMUL(double start_vol, double end_vol) {
235 for (size_t ch = 0; ch < data_.size(); ++ch) {
236 // First value should have original scaling applied.
237 EXPECT_FLOAT_EQ(expected_[ch][0] * start_vol, data_[ch][0]) << ch;
238
239 // Steady state have final scaling applied
240 int f = num_frames_ - 1;
241 EXPECT_FLOAT_EQ(expected_[ch][f] * end_vol, data_[ch][f]) << ch;
242 }
243 }
244
245 // Checks data_ = expected_ + slew_volume_(data_2_)
246 void CheckSlewMAC(double start_vol, double end_vol) {
247 for (size_t ch = 0; ch < data_.size(); ++ch) {
248 // First value should have original scaling applied.
249 EXPECT_FLOAT_EQ(expected_[ch][0] + data_2_[ch][0] * start_vol,
250 data_[ch][0])
251 << ch;
252
253 // Steady state have final scaling applied
254 int f = num_frames_ - 1;
255 EXPECT_FLOAT_EQ(expected_[ch][f] + data_2_[ch][f] * end_vol, data_[ch][f])
256 << ch << " " << f;
257 }
258 }
259
260 int sample_rate_;
261 int slew_time_ms_;
262 int slew_time_frames_;
263
264 private:
265 DISALLOW_COPY_AND_ASSIGN(SlewVolumeDynamicTest);
266 };
267
268 TEST_P(SlewVolumeDynamicTest, FMULRampUp) {
269 double start = 0.0;
270 double end = 1.0;
271 slew_volume_->SetVolume(start);
272 ClearInterrupted();
273
274 slew_volume_->SetVolume(end);
275 slew_volume_->ProcessFMUL(false, data_[0], num_frames_, data_[0]);
276 slew_volume_->ProcessFMUL(true, data_[1], num_frames_, data_[1]);
277 CheckSlewMUL(start, end);
278 }
279
280 TEST_P(SlewVolumeDynamicTest, FMULRampDown) {
281 double start = 1.0;
282 double end = 0.0;
283 slew_volume_->SetVolume(start);
284 ClearInterrupted();
285
286 slew_volume_->SetVolume(end);
287 slew_volume_->ProcessFMUL(false, data_[0], num_frames_, data_[0]);
288 slew_volume_->ProcessFMUL(true, data_[1], num_frames_, data_[1]);
289 CheckSlewMUL(start, end);
290 }
291
292 // Provide data as small buffers.
293 TEST_P(SlewVolumeDynamicTest, FMULRampDownByParts) {
294 double start = 1.0;
295 double end = 0.0;
296 slew_volume_->SetVolume(start);
297 ClearInterrupted();
298
299 slew_volume_->SetVolume(end);
300 int frame_step = ::media::vector_math::kRequiredAlignment / kBytesPerSample;
301 int f;
302 for (f = 0; f < num_frames_; f += frame_step) {
303 // Process any remaining samples in the last step.
304 if (num_frames_ - f < frame_step * 2) {
305 frame_step = num_frames_ - f;
306 }
307 slew_volume_->ProcessFMUL(false, expected_[0] + f, frame_step,
308 data_[0] + f);
309 slew_volume_->ProcessFMUL(true, expected_[1] + f, frame_step, data_[1] + f);
310 }
311 ASSERT_EQ(num_frames_, f);
312 CheckSlewMUL(start, end);
313 }
314
315 TEST_P(SlewVolumeDynamicTest, FMACRampUp) {
316 double start = 0.0;
317 double end = 1.0;
318 slew_volume_->SetVolume(start);
319 ClearInterrupted();
320
321 slew_volume_->SetVolume(end);
322 slew_volume_->ProcessFMAC(false, data_2_[0], num_frames_, data_[0]);
323 slew_volume_->ProcessFMAC(true, data_2_[1], num_frames_, data_[1]);
324 CheckSlewMAC(start, end);
325 }
326
327 TEST_P(SlewVolumeDynamicTest, FMACRampDown) {
328 double start = 1.0;
329 double end = 0.0;
330 slew_volume_->SetVolume(start);
331 ClearInterrupted();
332
333 slew_volume_->SetVolume(end);
334 slew_volume_->ProcessFMAC(false, data_2_[0], num_frames_, data_[0]);
335 slew_volume_->ProcessFMAC(true, data_2_[1], num_frames_, data_[1]);
336 CheckSlewMAC(start, end);
337 }
338
339 // Provide data as small buffers.
340 TEST_P(SlewVolumeDynamicTest, FMACRampUpByParts) {
341 double start = 0.0;
342 double end = 1.0;
343 slew_volume_->SetVolume(start);
344 ClearInterrupted();
345
346 slew_volume_->SetVolume(end);
347 int frame_step = ::media::vector_math::kRequiredAlignment / kBytesPerSample;
348 int f;
349 for (f = 0; f < num_frames_; f += frame_step) {
350 // Process any remaining samples in the last step.
351 if (num_frames_ - f < frame_step * 2) {
352 frame_step = num_frames_ - f;
353 }
354 slew_volume_->ProcessFMAC(false, data_2_[0] + f, frame_step, data_[0] + f);
355 slew_volume_->ProcessFMAC(true, data_2_[1] + f, frame_step, data_[1] + f);
356 }
357 ASSERT_EQ(num_frames_, f);
358 CheckSlewMAC(start, end);
359 }
360
361 INSTANTIATE_TEST_CASE_P(SingleBufferSlew,
362 SlewVolumeDynamicTest,
363 ::testing::Combine(::testing::Values(44100, 48000),
364 ::testing::Values(0, 15, 100)));
365 } // namespace media
366 } // namespace chromecast
OLDNEW
« no previous file with comments | « chromecast/media/cma/backend/alsa/slew_volume.cc ('k') | chromecast/public/media/audio_post_processor_shlib.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698