Chromium Code Reviews| Index: third_party/WebKit/Source/platform/audio/PushPullFIFOSmokeTest.cpp |
| diff --git a/third_party/WebKit/Source/platform/audio/PushPullFIFOSmokeTest.cpp b/third_party/WebKit/Source/platform/audio/PushPullFIFOSmokeTest.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..a03329cae01218d0c71ff913030073817e44c72a |
| --- /dev/null |
| +++ b/third_party/WebKit/Source/platform/audio/PushPullFIFOSmokeTest.cpp |
| @@ -0,0 +1,212 @@ |
| +// Copyright 2017 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "platform/audio/PushPullFIFO.h" |
| + |
| +#include <memory> |
| +#include <vector> |
| +#include "platform/CrossThreadFunctional.h" |
| +#include "platform/WaitableEvent.h" |
| +#include "platform/WebTaskRunner.h" |
| +#include "platform/audio/AudioUtilities.h" |
| +#include "platform/testing/UnitTestHelpers.h" |
| +#include "platform/wtf/Functional.h" |
| +#include "platform/wtf/PtrUtil.h" |
| +#include "public/platform/Platform.h" |
| +#include "public/platform/WebThread.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +namespace blink { |
| + |
| +namespace { |
| + |
| +// To forcibly stop the message loop. |
| +// TODO(hongchan): move this hack into Test class. |
| +void FinishTest() { |
| + LOG(INFO) << "FinishTest"; |
| + testing::ExitRunLoop(); |
| +} |
| + |
| +// To wait for spawned threads to finish their tasks. |
| +// TODO(hongchan): move this hack into Test class. |
|
o1ka
2017/04/25 08:23:22
Fix TODOs?
hongchan
2017/04/25 20:36:42
It seems to be impossible at the moment. Other Bli
|
| +void HoldTestForDuration(double duration_ms) { |
| + LOG(INFO) << "HoldTestForDuration"; |
| + Platform::Current()->CurrentThread()->GetWebTaskRunner()->PostDelayedTask( |
| + BLINK_FROM_HERE, |
| + WTF::Bind(&FinishTest), |
| + duration_ms); |
| + testing::EnterRunLoop(); |
| +} |
| + |
| +// Base FIFOClient with an extra thread for looping and jitter control. The |
| +// child class must define a specific task to run on the thread. |
| +class FIFOClient { |
| + public: |
| + FIFOClient(PushPullFIFO* fifo, size_t jitter_range_ms) |
| + : fifo_(fifo), |
| + jitter_range_ms_(jitter_range_ms), |
| + client_thread_(WTF::WrapUnique( |
| + Platform::Current()->CreateThread("client thread"))) {} |
| + |
| + void Start(double duration_ms, double interval_ms) { |
| + duration_ms_ = duration_ms; |
| + interval_ms_ = interval_ms; |
| + client_thread_->GetWebTaskRunner()->PostTask( |
| + BLINK_FROM_HERE, |
| + CrossThreadBind(&FIFOClient::RunTaskOnOwnThread, |
| + CrossThreadUnretained(this))); |
| + } |
| + |
| + virtual void RunTask() = 0; |
| + virtual void Stop() = 0; |
| + |
| + protected: |
| + RefPtr<AudioBus> bus_; |
| + PushPullFIFO* fifo_; |
| + double elapsed_ms_ = 0; |
| + int counter_ = 0; |
|
o1ka
2017/04/25 08:23:22
Could you refactor the code to make all the member
hongchan
2017/04/25 20:36:42
Done.
|
| + |
| + private: |
| + void RunTaskOnOwnThread() { |
| + double interval_with_jitter = interval_ms_ |
| + + (static_cast<double>(std::rand()) / RAND_MAX) * jitter_range_ms_; |
| + elapsed_ms_ += interval_with_jitter; |
| + ++counter_; |
| + RunTask(); |
| + if (elapsed_ms_ < duration_ms_) { |
| + client_thread_->GetWebTaskRunner()->PostDelayedTask( |
| + BLINK_FROM_HERE, |
| + CrossThreadBind(&FIFOClient::RunTaskOnOwnThread, |
| + CrossThreadUnretained(this)), |
| + interval_with_jitter); |
| + } else { |
| + Stop(); |
| + } |
| + } |
| + |
| + double duration_ms_; |
| + double interval_ms_; |
| + double jitter_range_ms_; |
|
o1ka
2017/04/25 08:23:22
Add comments for these members?
hongchan
2017/04/25 20:36:42
Done.
|
| + std::unique_ptr<WebThread> client_thread_; |
| +}; |
| + |
| +// FIFO-pulling client (consumer). This mimics the audio device thread. |
| +class PullClient : public FIFOClient { |
| + public: |
| + PullClient(PushPullFIFO* fifo, size_t frames_to_pull, double jitter_range_ms) |
| + : FIFOClient(fifo, jitter_range_ms), |
| + frames_to_pull_(frames_to_pull) { |
| + bus_ = AudioBus::Create(fifo_->NumberOfChannels(), frames_to_pull_); |
| + } |
| + |
| + void RunTask() override { |
| + fifo_->Pull(bus_.Get(), frames_to_pull_); |
| + } |
| + |
| + void Stop() override { |
| + LOG(INFO) << "PullClient::Stop (" << counter_ << "calls)"; |
| + } |
| + |
| + private: |
| + size_t frames_to_pull_; |
| +}; |
| + |
| +// FIFO-pushing client (producer). This mimics the WebAudio rendering thread. |
| +class PushClient : public FIFOClient { |
| + public: |
| + PushClient(PushPullFIFO* fifo, size_t frames_to_push, double jitter_range_ms) |
| + : FIFOClient(fifo, jitter_range_ms) { |
| + bus_ = AudioBus::Create(fifo_->NumberOfChannels(), frames_to_push); |
| + } |
| + |
| + void RunTask() override { |
| + fifo_->Push(bus_.Get()); |
| + } |
| + |
| + void Stop() override { |
| + LOG(INFO) << "PushClient::Stop (" << counter_ << "calls)"; |
| + } |
| +}; |
| + |
| +struct FIFOSmokeTestParam { |
| + const double sample_rate; |
| + const unsigned number_of_channels; |
| + const size_t fifo_length; |
| + const double test_duration_ms; |
| + // Buffer size for pulling. Equivalent of |callback_buffer_size|. |
| + const size_t pull_buffer_size; |
| + // Jitter added to the regular pulling interval, where j is |
| + // 0 < j < jitter_range_ms. |
| + const double pull_jitter_range_ms; |
| + // Buffer size for pushing. Equivalent of WebAudio render quantum. |
| + const size_t push_buffer_size; |
| + // Jitter range for the pushing interval. |
| + const double push_jitter_range_ms; |
| +}; |
| + |
| +class PushPullFIFOSmokeTest |
| + : public ::testing::TestWithParam<FIFOSmokeTestParam> {}; |
| + |
| +TEST_P(PushPullFIFOSmokeTest, SmokeTests) { |
| + const FIFOSmokeTestParam param = GetParam(); |
| + const double sample_rate = param.sample_rate * 4; |
| + |
| + const double pull_interval_ms = |
| + param.pull_buffer_size / sample_rate * 1000; |
| + const double push_interval_ms = |
| + param.push_buffer_size / sample_rate * 1000; |
| + |
| + std::unique_ptr<PushPullFIFO> test_fifo = WTF::WrapUnique( |
| + new PushPullFIFO(param.number_of_channels, param.fifo_length)); |
| + std::unique_ptr<PullClient> pull_client = WTF::WrapUnique(new PullClient( |
| + test_fifo.get(), param.pull_buffer_size, param.pull_jitter_range_ms)); |
| + std::unique_ptr<PushClient> push_client = WTF::WrapUnique(new PushClient( |
| + test_fifo.get(), param.push_buffer_size, param.push_jitter_range_ms)); |
| + |
| + LOG(INFO) << "PushPullFIFOSmokeTest - Start"; |
| + |
| + pull_client->Start(param.test_duration_ms, pull_interval_ms); |
| + push_client->Start(param.test_duration_ms, push_interval_ms); |
| + |
| + // If the operation does not cause a crash for the test period, it's passed. |
| + // Also give a bit more time to finish the tear-down process. |
| + HoldTestForDuration(param.test_duration_ms + 150); |
| +} |
| + |
| +FIFOSmokeTestParam smoke_test_params[] = { |
| + // Test case 0 (OSX): 256 Pull, 128 Push, Minimal jitter. |
| + // WebThread's priority is lower than the device thread, so its jitter range |
| + // is slightly bigger than the other. |
| + {48000, 2, 8192, 1000, 256, 1, 128, 2}, |
| + |
| + // Test case 1 (Windows): 480 Pull, 128 Push. Moderate Jitter. |
|
o1ka
2017/04/25 08:23:22
Since WebAudio has introduced user-specified buffe
hongchan
2017/04/25 20:36:42
10ms = 480. (in 48000Hz)
I can do 960 as well if
|
| + // Windows' audio callback is known to be ~10ms and UMA data shows the |
| + // evidence for it. The jitter range was determined speculatively. |
| + {48000, 2, 8192, 1000, 480, 2, 128, 3}, |
| + |
| + // Test case 2 (Ubuntu/Linux): 512 Pull, 128 Push. Unstable callback, but |
| + // fast CPU. A typical configuration for Ubuntu + PulseAudio setup. |
| + // PulseAudio's callback is known to be rather unstable. |
| + {48000, 2, 8192, 1000, 512, 8, 128, 1}, |
| + |
| + // Test case 3 (Android-Reference): 512 Pull, 128 Push. Similar to Linux, but |
| + // low profile CPU. |
| + {44100, 2, 8192, 1000, 512, 8, 128, 3}, |
| + |
| + // Test case 4 (Android-ExternalA): 441 Pull, 128 Push. Extreme jitter with |
| + // low profile CPU. |
| + {44100, 2, 8192, 1000, 441, 24, 128, 8}, |
| + |
| + // Test case 5 (Android-ExternalB): 5768 Pull, 128 Push. Huge callback with |
| + // large jitter. Low profile CPU. |
| + {44100, 2, 8192, 1000, 5768, 120, 128, 12} |
|
o1ka
2017/04/25 08:23:22
Consider running at least one test for a longer ti
hongchan
2017/04/25 20:36:42
Good idea. Done.
|
| +}; |
| + |
| +INSTANTIATE_TEST_CASE_P(PushPullFIFOSmokeTest, |
| + PushPullFIFOSmokeTest, |
| + ::testing::ValuesIn(smoke_test_params)); |
| + |
| +} // namespace |
| + |
| +} // namespace blink |