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 "third_party/blink/renderer/platform/audio/push_pull_fifo.h"
6
7 #include <memory>
8 #include <vector>
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "third_party/blink/public/platform/platform.h"
11 #include "third_party/blink/renderer/platform/audio/audio_utilities.h"
12 #include "third_party/blink/renderer/platform/scheduler/public/thread.h"
13 #include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
14 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
15 #include "third_party/blink/renderer/platform/wtf/functional.h"
16
17 namespace blink {
18
19 namespace {
20
21 // Check the basic contract of FIFO. This test only covers the single thread
22 // scenario.
TEST(PushPullFIFOBasicTest,BasicTests)23 TEST(PushPullFIFOBasicTest, BasicTests) {
24 // This suppresses the multi-thread warning for GTest. Potently it increases
25 // the test execution time, but this specific test is very short and simple.
26 testing::FLAGS_gtest_death_test_style = "threadsafe";
27
28 // FIFO length exceeding the maximum length allowed will cause crash.
29 // i.e.) fifo_length_ <= kMaxFIFOLength
30 EXPECT_DEATH(new PushPullFIFO(2, PushPullFIFO::kMaxFIFOLength + 1), "");
31
32 std::unique_ptr<PushPullFIFO> test_fifo =
33 std::make_unique<PushPullFIFO>(2, 1024);
34
35 // The input bus length must be |audio_utilities::kRenderQuantumFrames|.
36 // i.e.) input_bus->length() == kRenderQuantumFrames
37 scoped_refptr<AudioBus> input_bus_129_frames =
38 AudioBus::Create(2, audio_utilities::kRenderQuantumFrames + 1);
39 EXPECT_DEATH(test_fifo->Push(input_bus_129_frames.get()), "");
40 scoped_refptr<AudioBus> input_bus_127_frames =
41 AudioBus::Create(2, audio_utilities::kRenderQuantumFrames - 1);
42 EXPECT_DEATH(test_fifo->Push(input_bus_127_frames.get()), "");
43
44 // Pull request frames cannot exceed the length of output bus.
45 // i.e.) frames_requested <= output_bus->length()
46 scoped_refptr<AudioBus> output_bus_512_frames = AudioBus::Create(2, 512);
47 EXPECT_DEATH(test_fifo->Pull(output_bus_512_frames.get(), 513), "");
48
49 // Pull request frames cannot exceed the length of FIFO.
50 // i.e.) frames_requested <= fifo_length_
51 scoped_refptr<AudioBus> output_bus_1025_frames = AudioBus::Create(2, 1025);
52 EXPECT_DEATH(test_fifo->Pull(output_bus_1025_frames.get(), 1025), "");
53 }
54
55 // Fills each AudioChannel in an AudioBus with a series of linearly increasing
56 // values starting from |starting_value| and incrementing by 1. Then return
57 // value will be |starting_value| + |bus_length|.
FillBusWithLinearRamp(AudioBus * target_bus,size_t starting_value)58 size_t FillBusWithLinearRamp(AudioBus* target_bus, size_t starting_value) {
59 for (unsigned c = 0; c < target_bus->NumberOfChannels(); ++c) {
60 float* bus_channel = target_bus->Channel(c)->MutableData();
61 for (size_t i = 0; i < target_bus->Channel(c)->length(); ++i) {
62 bus_channel[i] = static_cast<float>(starting_value + i);
63 }
64 }
65 return starting_value + target_bus->length();
66 }
67
68 // Inspect the content of AudioBus with a given set of index and value across
69 // channels.
VerifyBusValueAtIndex(AudioBus * target_bus,int index,float expected_value)70 bool VerifyBusValueAtIndex(AudioBus* target_bus,
71 int index,
72 float expected_value) {
73 for (unsigned c = 0; c < target_bus->NumberOfChannels(); ++c) {
74 float* bus_channel = target_bus->Channel(c)->MutableData();
75 if (bus_channel[index] != expected_value) {
76 LOG(ERROR) << ">> [FAIL] expected " << expected_value << " at index "
77 << index << " but got " << bus_channel[index] << ".";
78 return false;
79 }
80 }
81 return true;
82 }
83
84 struct FIFOAction {
85 // The type of action; "PUSH" or "PULL".
86 const char* action;
87 // Number of frames for the operation.
88 const size_t number_of_frames;
89 };
90
91 struct AudioBusSample {
92 // The frame index of a sample in the bus.
93 const size_t index;
94 // The value at the |index| above.
95 const float value;
96 };
97
98 struct FIFOTestSetup {
99 // Length of FIFO to be created for test case.
100 const size_t fifo_length;
101 // Channel count of FIFO to be created for test case.
102 const unsigned number_of_channels;
103 // A list of |FIFOAction| entries to be performed in test case.
104 const std::vector<FIFOAction> fifo_actions;
105 };
106
107 struct FIFOTestExpectedState {
108 // Expected read index in FIFO.
109 const size_t index_read;
110 // Expected write index in FIFO.
111 const size_t index_write;
112 // Expected overflow count in FIFO.
113 const unsigned overflow_count;
114 // Expected underflow count in FIFO.
115 const unsigned underflow_count;
116 // A list of expected |AudioBusSample| entries for the FIFO bus.
117 const std::vector<AudioBusSample> fifo_samples;
118 // A list of expected |AudioBusSample| entries for the output bus.
119 const std::vector<AudioBusSample> output_samples;
120 };
121
122 // The data structure for the parameterized test cases.
123 struct FIFOTestParam {
124 FIFOTestSetup setup;
125 FIFOTestExpectedState expected_state;
126 };
127
operator <<(std::ostream & out,const FIFOTestParam & param)128 std::ostream& operator<<(std::ostream& out, const FIFOTestParam& param) {
129 out << "fifoLength=" << param.setup.fifo_length
130 << " numberOfChannels=" << param.setup.number_of_channels;
131 return out;
132 }
133
134 class PushPullFIFOFeatureTest : public testing::TestWithParam<FIFOTestParam> {};
135
TEST_P(PushPullFIFOFeatureTest,FeatureTests)136 TEST_P(PushPullFIFOFeatureTest, FeatureTests) {
137 const FIFOTestSetup setup = GetParam().setup;
138 const FIFOTestExpectedState expected_state = GetParam().expected_state;
139
140 // Create a FIFO with a specified configuration.
141 std::unique_ptr<PushPullFIFO> fifo = std::make_unique<PushPullFIFO>(
142 setup.number_of_channels, setup.fifo_length);
143
144 scoped_refptr<AudioBus> output_bus;
145
146 // Iterate all the scheduled push/pull actions.
147 size_t frame_counter = 0;
148 for (const auto& action : setup.fifo_actions) {
149 if (strcmp(action.action, "PUSH") == 0) {
150 scoped_refptr<AudioBus> input_bus =
151 AudioBus::Create(setup.number_of_channels, action.number_of_frames);
152 frame_counter = FillBusWithLinearRamp(input_bus.get(), frame_counter);
153 fifo->Push(input_bus.get());
154 LOG(INFO) << "PUSH " << action.number_of_frames
155 << " frames (frameCounter=" << frame_counter << ")";
156 } else {
157 output_bus =
158 AudioBus::Create(setup.number_of_channels, action.number_of_frames);
159 fifo->Pull(output_bus.get(), action.number_of_frames);
160 LOG(INFO) << "PULL " << action.number_of_frames << " frames";
161 }
162 }
163
164 // Get FIFO config data.
165 const PushPullFIFOStateForTest actual_state = fifo->GetStateForTest();
166
167 // Verify the read/write indexes.
168 EXPECT_EQ(expected_state.index_read, actual_state.index_read);
169 EXPECT_EQ(expected_state.index_write, actual_state.index_write);
170 EXPECT_EQ(expected_state.overflow_count, actual_state.overflow_count);
171 EXPECT_EQ(expected_state.underflow_count, actual_state.underflow_count);
172
173 // Verify in-FIFO samples.
174 for (const auto& sample : expected_state.fifo_samples) {
175 EXPECT_TRUE(VerifyBusValueAtIndex(fifo->GetFIFOBusForTest(),
176 sample.index, sample.value));
177 }
178
179 // Verify samples from the most recent output bus.
180 for (const auto& sample : expected_state.output_samples) {
181 EXPECT_TRUE(
182 VerifyBusValueAtIndex(output_bus.get(), sample.index, sample.value));
183 }
184 }
185
186 FIFOTestParam g_feature_test_params[] = {
187 // Test cases 0 ~ 3: Regular operation on various channel configuration.
188 // - Mono, Stereo, Quad, 5.1.
189 // - FIFO length and pull size are RQ-aligned.
190 {{512, 1, {{"PUSH", 128}, {"PUSH", 128}, {"PULL", 256}}},
191 {256, 256, 0, 0, {{0, 0}}, {{0, 0}, {255, 255}}}},
192
193 {{512, 2, {{"PUSH", 128}, {"PUSH", 128}, {"PULL", 256}}},
194 {256, 256, 0, 0, {{0, 0}}, {{0, 0}, {255, 255}}}},
195
196 {{512, 4, {{"PUSH", 128}, {"PUSH", 128}, {"PULL", 256}}},
197 {256, 256, 0, 0, {{0, 0}}, {{0, 0}, {255, 255}}}},
198
199 {{512, 6, {{"PUSH", 128}, {"PUSH", 128}, {"PULL", 256}}},
200 {256, 256, 0, 0, {{0, 0}}, {{0, 0}, {255, 255}}}},
201
202 // Test case 4: Pull size less than or equal to 128.
203 {{128, 2, {{"PUSH", 128}, {"PULL", 128}, {"PUSH", 128}, {"PULL", 64}}},
204 {64, 0, 0, 0, {{64, 192}, {0, 128}}, {{0, 128}, {63, 191}}}},
205
206 // Test case 5: Unusual FIFO and Pull length.
207 // - FIFO and pull length that are not aligned to render quantum.
208 // - Check if the indexes are wrapping around correctly.
209 // - Check if the output bus starts and ends with correct values.
210 {{997,
211 1,
212 {
213 {"PUSH", 128},
214 {"PUSH", 128},
215 {"PUSH", 128},
216 {"PUSH", 128},
217 {"PULL", 449},
218 {"PUSH", 128},
219 {"PUSH", 128},
220 {"PUSH", 128},
221 {"PUSH", 128},
222 {"PULL", 449},
223 }},
224 // - expectedIndexRead = 898, expectedIndexWrite = 27
225 // - overflowCount = 0, underflowCount = 0
226 // - FIFO samples (index, expectedValue) = (898, 898), (27, 27)
227 // - Output bus samples (index, expectedValue) = (0, 499), (448, 897)
228 {898, 27, 0, 0, {{898, 898}, {27, 27}}, {{0, 449}, {448, 897}}}},
229
230 // Test case 6: Overflow
231 // - Check overflow counter.
232 // - After the overflow occurs, the read index must be moved to the write
233 // index. Thus pulled frames must not contain overwritten data.
234 {{512,
235 3,
236 {
237 {"PUSH", 128},
238 {"PUSH", 128},
239 {"PUSH", 128},
240 {"PUSH", 128},
241 {"PUSH", 128},
242 {"PULL", 256},
243 }},
244 // - expectedIndexRead = 384, expectedIndexWrite = 128
245 // - overflowCount = 1, underflowCount = 0
246 // - FIFO samples (index, expectedValue) = (384, 384), (128, 128)
247 // - Output bus samples (index, expectedValue) = (0, 128), (255, 383)
248 {384, 128, 1, 0, {{384, 384}, {128, 128}}, {{0, 128}, {255, 383}}}},
249
250 // Test case 7: Overflow in unusual FIFO and pull length.
251 // - Check overflow counter.
252 // - After the overflow occurs, the read index must be moved to the write
253 // index. Thus pulled frames must not contain overwritten data.
254 {{577,
255 5,
256 {
257 {"PUSH", 128},
258 {"PUSH", 128},
259 {"PUSH", 128},
260 {"PUSH", 128},
261 {"PUSH", 128},
262 {"PULL", 227},
263 }},
264 // - expectedIndexRead = 290, expectedIndexWrite = 63
265 // - overflowCount = 1, underflowCount = 0
266 // - FIFO samples (index, expectedValue) = (63, 63), (290, 290)
267 // - Output bus samples (index, expectedValue) = (0, 63), (226, 289)
268 {290, 63, 1, 0, {{63, 63}, {290, 290}}, {{0, 63}, {226, 289}}}},
269
270 // Test case 8: Underflow
271 // - Check underflow counter.
272 // - After the underflow occurs, the write index must be moved to the read
273 // index. Frames pulled after FIFO underflows must be zeroed.
274 {{512,
275 7,
276 {
277 {"PUSH", 128},
278 {"PUSH", 128},
279 {"PUSH", 128},
280 {"PULL", 384},
281 {"PUSH", 128},
282 {"PUSH", 128},
283 {"PULL", 384},
284 }},
285 // - expectedIndexRead = 128, expectedIndexWrite = 128
286 // - overflowCount = 0, underflowCount = 1
287 // - FIFO samples (index, expectedValue) = (128, 128)
288 // - Output bus samples (index, expectedValue) = (0, 384), (255, 639)
289 // (256, 0), (383, 0)
290 {128,
291 128,
292 0,
293 1,
294 {{128, 128}},
295 {{0, 384}, {255, 639}, {256, 0}, {383, 0}}}},
296
297 // Test case 9: Underflow in unusual FIFO and pull length.
298 // - Check underflow counter.
299 // - After the underflow occurs, the write index must be moved to the read
300 // index. Frames pulled after FIFO underflows must be zeroed.
301 {{523,
302 11,
303 {
304 {"PUSH", 128},
305 {"PUSH", 128},
306 {"PUSH", 128},
307 {"PULL", 383},
308 {"PUSH", 128},
309 {"PUSH", 128},
310 {"PULL", 383},
311 }},
312 // - expectedIndexRead = 117, expectedIndexWrite = 117
313 // - overflowCount = 0, underflowCount = 1
314 // - FIFO samples (index, expectedValue) = (117, 117)
315 // - Output bus samples (index, expectedValue) = (0, 383), (256, 639)
316 // (257, 0), (382, 0)
317 {117,
318 117,
319 0,
320 1,
321 {{117, 117}},
322 {{0, 383}, {256, 639}, {257, 0}, {382, 0}}}},
323
324 // Test case 10: Multiple pull from an empty FIFO.
325 // - Check underflow counter.
326 // - After the underflow occurs, the write index must be moved to the read
327 // index. Frames pulled after FIFO underflows must be zeroed.
328 {{1024,
329 11,
330 {
331 {"PUSH", 128},
332 {"PUSH", 128},
333 {"PULL", 440},
334 {"PULL", 440},
335 {"PULL", 440},
336 {"PULL", 440},
337 {"PULL", 440},
338 }},
339 // - expectedIndexRead = 117, expectedIndexWrite = 117
340 // - overflowCount = 0, underflowCount = 1
341 // - FIFO samples (index, expectedValue) = (117, 117)
342 // - Output bus samples (index, expectedValue) = (0, 383), (256, 639)
343 // (257, 0), (382, 0)
344 {256, 256, 0, 5, {{256, 0}}, {{0, 0}, {439, 0}}}},
345
346 // Test case 11: Multiple pull from an empty FIFO. (zero push)
347 {{1024,
348 11,
349 {
350 {"PULL", 144},
351 {"PULL", 144},
352 {"PULL", 144},
353 {"PULL", 144},
354 }},
355 // - expectedIndexRead = 0, expectedIndexWrite = 0
356 // - overflowCount = 0, underflowCount = 4
357 // - FIFO samples (index, expectedValue) = (0, 0), (1023, 0)
358 // - Output bus samples (index, expectedValue) = (0, 0), (143, 0)
359 {0, 0, 0, 4, {{0, 0}, {1023, 0}}, {{0, 0}, {143, 0}}}}};
360
361 INSTANTIATE_TEST_SUITE_P(PushPullFIFOFeatureTest,
362 PushPullFIFOFeatureTest,
363 testing::ValuesIn(g_feature_test_params));
364
365 } // namespace
366
367 } // namespace blink
368