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