// Copyright 2016 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 "media/base/audio_latency.h" #include #include "base/time/time.h" #include "build/build_config.h" #include "media/base/limits.h" #include "testing/gtest/include/gtest/gtest.h" namespace media { // Tuple of . using AudioLatencyTestData = std::tuple; class AudioLatencyTest : public testing::TestWithParam { public: AudioLatencyTest() = default; ~AudioLatencyTest() override = default; void TestExactBufferSizes() { const int hardware_sample_rate = std::get<0>(GetParam()); const int hardware_buffer_size = std::get<1>(GetParam()); const int min_buffer_size = std::get<2>(GetParam()); const int max_buffer_size = std::get<3>(GetParam()); const int platform_min_buffer_size = min_buffer_size ? min_buffer_size : hardware_buffer_size; // Windows 10 may allow exactly the minimum buffer size using the IAudioClient3 // API but any other buffer size must be a multiple of the hardware_buffer_size // and not the min_buffer_size. #if BUILDFLAG(IS_WIN) const int multiplier = hardware_buffer_size; #else const int multiplier = platform_min_buffer_size; #endif const int platform_max_buffer_size = max_buffer_size ? (limits::kMaxWebAudioBufferSize / max_buffer_size) * max_buffer_size : (limits::kMaxWebAudioBufferSize / multiplier) * multiplier; EXPECT_EQ( platform_min_buffer_size, media::AudioLatency::GetExactBufferSize( base::Seconds(0.0), hardware_sample_rate, hardware_buffer_size, min_buffer_size, max_buffer_size, limits::kMaxWebAudioBufferSize)); EXPECT_EQ(platform_min_buffer_size, media::AudioLatency::GetExactBufferSize( base::Seconds(min_buffer_size / static_cast(hardware_sample_rate)), hardware_sample_rate, hardware_buffer_size, min_buffer_size, max_buffer_size, limits::kMaxWebAudioBufferSize)); EXPECT_EQ(multiplier * 2, media::AudioLatency::GetExactBufferSize( base::Seconds((multiplier * 2) / static_cast(hardware_sample_rate)), hardware_sample_rate, hardware_buffer_size, min_buffer_size, max_buffer_size, limits::kMaxWebAudioBufferSize)); EXPECT_EQ(multiplier * 2, media::AudioLatency::GetExactBufferSize( base::Seconds((multiplier * 1.1) / static_cast(hardware_sample_rate)), hardware_sample_rate, hardware_buffer_size, min_buffer_size, max_buffer_size, limits::kMaxWebAudioBufferSize)); EXPECT_EQ( platform_max_buffer_size, media::AudioLatency::GetExactBufferSize( base::Seconds(10.0), hardware_sample_rate, hardware_buffer_size, min_buffer_size, max_buffer_size, limits::kMaxWebAudioBufferSize)); if (max_buffer_size) { EXPECT_EQ(max_buffer_size, media::AudioLatency::GetExactBufferSize( base::Seconds(max_buffer_size / static_cast(hardware_sample_rate)), hardware_sample_rate, hardware_buffer_size, min_buffer_size, max_buffer_size, limits::kMaxWebAudioBufferSize)); } #if BUILDFLAG(IS_WIN) if (min_buffer_size && min_buffer_size < hardware_buffer_size) { EXPECT_EQ(hardware_buffer_size, media::AudioLatency::GetExactBufferSize( base::Seconds((min_buffer_size * 1.1) / static_cast(hardware_sample_rate)), hardware_sample_rate, hardware_buffer_size, min_buffer_size, max_buffer_size, limits::kMaxWebAudioBufferSize)); } #elif BUILDFLAG(IS_MAC) EXPECT_EQ(limits::kMaxWebAudioBufferSize, media::AudioLatency::GetExactBufferSize( base::Seconds((limits::kMaxAudioBufferSize * 1.1) / static_cast(hardware_sample_rate)), hardware_sample_rate, hardware_buffer_size, min_buffer_size, max_buffer_size, limits::kMaxWebAudioBufferSize)); #endif int previous_buffer_size = 0; for (int i = 0; i < 1000; i++) { int buffer_size = media::AudioLatency::GetExactBufferSize( base::Seconds(i / 1000.0), hardware_sample_rate, hardware_buffer_size, min_buffer_size, max_buffer_size, limits::kMaxWebAudioBufferSize); EXPECT_GE(buffer_size, previous_buffer_size); #if BUILDFLAG(IS_WIN) EXPECT_TRUE(buffer_size == min_buffer_size || buffer_size % multiplier == 0 || buffer_size % max_buffer_size == 0); #else EXPECT_EQ(buffer_size, buffer_size / multiplier * multiplier); #endif previous_buffer_size = buffer_size; } } }; // TODO(olka): extend unit tests, use real-world sample rates. TEST(AudioLatency, HighLatencyBufferSizes) { #if BUILDFLAG(IS_WIN) for (int i = 6400; i <= 204800; i *= 2) { EXPECT_EQ(2 * (i / 100), AudioLatency::GetHighLatencyBufferSize(i, i / 100)); } #else for (int i = 6400; i <= 204800; i *= 2) #if defined(USE_CRAS) EXPECT_EQ(8 * (i / 100), AudioLatency::GetHighLatencyBufferSize(i, 32)); #else EXPECT_EQ(2 * (i / 100), AudioLatency::GetHighLatencyBufferSize(i, 32)); #endif // defined(USE_CRAS) #endif // BUILDFLAG(IS_WIN) } TEST(AudioLatency, InteractiveBufferSizes) { // The |first| is a requested buffer size and and the |second| is a computed // "interactive" buffer size from the method. std::vector> buffer_size_pairs = { #if BUILDFLAG(IS_ANDROID) {64, 128}, {96, 384}, // Pixel 3, 4, 5. (See crbug.com/1090441) {240, 240}, // Nexus 7 {144, 144}, // Galaxy Nexus // Irregular device buffer size {100, 512}, {127, 512}, #else {64, 64}, #endif // BUILDFLAG(IS_ANDROID) {128, 128}, {256, 256}, {512, 512}, {1024, 1024}, {2048, 2048} }; for (auto & buffer_size_pair : buffer_size_pairs) { EXPECT_EQ(buffer_size_pair.second, AudioLatency::GetInteractiveBufferSize(buffer_size_pair.first)); } } TEST(AudioLatency, RtcBufferSizes) { for (int i = 6400; i < 204800; i *= 2) { EXPECT_EQ(i / 100, AudioLatency::GetRtcBufferSize(i, 0)); #if BUILDFLAG(IS_WIN) EXPECT_EQ(500, AudioLatency::GetRtcBufferSize(i, 500)); #elif BUILDFLAG(IS_ANDROID) EXPECT_EQ(i / 50, AudioLatency::GetRtcBufferSize(i, i / 50 - 1)); EXPECT_EQ(i / 50 + 1, AudioLatency::GetRtcBufferSize(i, i / 50 + 1)); #else EXPECT_EQ(i / 100, AudioLatency::GetRtcBufferSize(i, 500)); #endif // BUILDFLAG(IS_WIN) } } TEST_P(AudioLatencyTest, ExactBufferSizes) { TestExactBufferSizes(); } INSTANTIATE_TEST_SUITE_P( All, AudioLatencyTest, #if BUILDFLAG(IS_WIN) // Windows 10 with supported driver will have valid min and max buffer sizes // whereas older Windows will have zeros. The specific min, max and hardware // are device-dependent. testing::Values(std::make_tuple(44100, 440, 128, 440), std::make_tuple(44100, 440, 440, 440), std::make_tuple(44100, 440, 440, 880), std::make_tuple(44100, 440, 440, 4400), std::make_tuple(44100, 440, 128, 4196), std::make_tuple(44100, 440, 440, 4196), std::make_tuple(44100, 440, 0, 0), std::make_tuple(44100, 256, 128, 512), std::make_tuple(44100, 256, 0, 0)) #elif BUILDFLAG(IS_MAC) || defined(USE_CRAS) // These values are constant on Mac and ChromeOS, regardless of device. testing::Values(std::make_tuple(44100, 256, limits::kMinAudioBufferSize, limits::kMaxAudioBufferSize)) #else testing::Values(std::make_tuple(44100, 256, 0, 0), std::make_tuple(44100, 440, 0, 0)) #endif ); } // namespace media