diff options
author | dalecurtis@chromium.org <dalecurtis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-17 06:06:45 +0000 |
---|---|---|
committer | dalecurtis@chromium.org <dalecurtis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-17 06:06:45 +0000 |
commit | 64e0e3b22059b006a2119a14887901f287c9f35e (patch) | |
tree | 129c9117a5d1e1abee5dc9d00c8d43ab48fb7e79 /media | |
parent | f212ee13b64f6ced8d0948d51f7c1ac841ecc74d (diff) | |
download | chromium_src-64e0e3b22059b006a2119a14887901f287c9f35e.zip chromium_src-64e0e3b22059b006a2119a14887901f287c9f35e.tar.gz chromium_src-64e0e3b22059b006a2119a14887901f287c9f35e.tar.bz2 |
Use larger buffer sizes for lower power on Linux.
HTML5 playback on Linux ALSA, Pulse, and ChromeOS will now use a
buffer size of 1024+ for media playback.
On my Z620 this takes pulseaudio daemon CPU usage from a solid 3-4%
down to 1%. Likely there are savings in the Chrome process as well,
but those are harder to measure against process noise.
I suspect we'll see greater savings on Chromebooks.
BUG=362261
TEST=Audio sounds the same always. CPU usage down.
NOTRY=true
Review URL: https://codereview.chromium.org/235723003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@264443 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/audio/cras/audio_manager_cras.cc | 12 | ||||
-rw-r--r-- | media/audio/pulse/audio_manager_pulse.cc | 11 | ||||
-rw-r--r-- | media/base/audio_hardware_config.cc | 52 | ||||
-rw-r--r-- | media/base/audio_hardware_config.h | 4 | ||||
-rw-r--r-- | media/base/audio_hardware_config_unittest.cc | 33 | ||||
-rw-r--r-- | media/filters/audio_renderer_impl.cc | 9 |
6 files changed, 111 insertions, 10 deletions
diff --git a/media/audio/cras/audio_manager_cras.cc b/media/audio/cras/audio_manager_cras.cc index ee7cc9c..53f36ab 100644 --- a/media/audio/cras/audio_manager_cras.cc +++ b/media/audio/cras/audio_manager_cras.cc @@ -30,6 +30,10 @@ static const int kMaxOutputStreams = 50; // Default sample rate for input and output streams. static const int kDefaultSampleRate = 48000; +// Define bounds for the output buffer size. +static const int kMinimumOutputBufferSize = 512; +static const int kMaximumOutputBufferSize = 8192; + bool AudioManagerCras::HasAudioOutputDevices() { return true; } @@ -103,11 +107,9 @@ AudioParameters AudioManagerCras::GetPreferredOutputStreamParameters( const AudioParameters& input_params) { // TODO(tommi): Support |output_device_id|. DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!"; - static const int kDefaultOutputBufferSize = 512; - ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; int sample_rate = kDefaultSampleRate; - int buffer_size = kDefaultOutputBufferSize; + int buffer_size = kMinimumOutputBufferSize; int bits_per_sample = 16; int input_channels = 0; if (input_params.IsValid()) { @@ -115,7 +117,9 @@ AudioParameters AudioManagerCras::GetPreferredOutputStreamParameters( bits_per_sample = input_params.bits_per_sample(); channel_layout = input_params.channel_layout(); input_channels = input_params.input_channels(); - buffer_size = input_params.frames_per_buffer(); + buffer_size = + std::min(kMaximumOutputBufferSize, + std::max(buffer_size, input_params.frames_per_buffer())); } int user_buffer_size = GetUserBufferSize(); diff --git a/media/audio/pulse/audio_manager_pulse.cc b/media/audio/pulse/audio_manager_pulse.cc index 3369fd5..238530a 100644 --- a/media/audio/pulse/audio_manager_pulse.cc +++ b/media/audio/pulse/audio_manager_pulse.cc @@ -35,6 +35,10 @@ using pulse::WaitForOperationCompletion; // Maximum number of output streams that can be open simultaneously. static const int kMaxOutputStreams = 50; +// Define bounds for the output buffer size. +static const int kMinimumOutputBufferSize = 512; +static const int kMaximumOutputBufferSize = 8192; + static const base::FilePath::CharType kPulseLib[] = FILE_PATH_LITERAL("libpulse.so.0"); @@ -161,10 +165,9 @@ AudioParameters AudioManagerPulse::GetPreferredOutputStreamParameters( const AudioParameters& input_params) { // TODO(tommi): Support |output_device_id|. VLOG_IF(0, !output_device_id.empty()) << "Not implemented!"; - static const int kDefaultOutputBufferSize = 512; ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; - int buffer_size = kDefaultOutputBufferSize; + int buffer_size = kMinimumOutputBufferSize; int bits_per_sample = 16; int input_channels = 0; int sample_rate; @@ -172,7 +175,9 @@ AudioParameters AudioManagerPulse::GetPreferredOutputStreamParameters( bits_per_sample = input_params.bits_per_sample(); channel_layout = input_params.channel_layout(); input_channels = input_params.input_channels(); - buffer_size = std::min(buffer_size, input_params.frames_per_buffer()); + buffer_size = + std::min(kMaximumOutputBufferSize, + std::max(buffer_size, input_params.frames_per_buffer())); sample_rate = input_params.sample_rate(); } else { sample_rate = GetNativeSampleRate(); diff --git a/media/base/audio_hardware_config.cc b/media/base/audio_hardware_config.cc index d72fce7..959b90c 100644 --- a/media/base/audio_hardware_config.cc +++ b/media/base/audio_hardware_config.cc @@ -4,17 +4,40 @@ #include "media/base/audio_hardware_config.h" +#include <algorithm> + +#include "base/logging.h" +#include "build/build_config.h" + using base::AutoLock; using media::AudioParameters; namespace media { +#if defined(OS_LINUX) +#define HIGH_LATENCY_AUDIO_SUPPORT 1 +#endif + +#if defined(HIGH_LATENCY_AUDIO_SUPPORT) +// Taken from "Bit Twiddling Hacks" +// http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 +static uint32_t RoundUpToPowerOfTwo(uint32_t v) { + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; +} +#endif + AudioHardwareConfig::AudioHardwareConfig( const AudioParameters& input_params, const AudioParameters& output_params) : input_params_(input_params), - output_params_(output_params) { -} + output_params_(output_params) {} AudioHardwareConfig::~AudioHardwareConfig() {} @@ -77,4 +100,29 @@ void AudioHardwareConfig::UpdateOutputConfig( output_params_ = output_params; } +int AudioHardwareConfig::GetHighLatencyBufferSize() const { + AutoLock auto_lock(config_lock_); +#if defined(HIGH_LATENCY_AUDIO_SUPPORT) + // Empirically, use the nearest higher power of two buffer size corresponding + // to 20 ms worth of samples. For a given sample rate, this works out to: + // + // <= 3200 : 64 + // <= 6400 : 128 + // <= 12800 : 256 + // <= 25600 : 512 + // <= 51200 : 1024 + // <= 102400 : 2048 + // <= 204800 : 4096 + // + // On Linux, the minimum hardware buffer size is 512, so the lower calculated + // values are unused. OSX may have a value as low as 128. Windows is device + // dependent but will generally be sample_rate() / 100. + const int high_latency_buffer_size = + RoundUpToPowerOfTwo(2 * output_params_.sample_rate() / 100); + return std::max(output_params_.frames_per_buffer(), high_latency_buffer_size); +#else + return output_params_.frames_per_buffer(); +#endif +} + } // namespace media diff --git a/media/base/audio_hardware_config.h b/media/base/audio_hardware_config.h index d1621b98..a4baaac 100644 --- a/media/base/audio_hardware_config.h +++ b/media/base/audio_hardware_config.h @@ -41,6 +41,10 @@ class MEDIA_EXPORT AudioHardwareConfig { void UpdateInputConfig(const media::AudioParameters& input_params); void UpdateOutputConfig(const media::AudioParameters& output_params); + // For clients which don't need low latency, a larger buffer size should be + // used to save power and CPU resources. + int GetHighLatencyBufferSize() const; + private: // Cached values; access is protected by |config_lock_|. mutable base::Lock config_lock_; diff --git a/media/base/audio_hardware_config_unittest.cc b/media/base/audio_hardware_config_unittest.cc index 4a742bf..357ddca 100644 --- a/media/base/audio_hardware_config_unittest.cc +++ b/media/base/audio_hardware_config_unittest.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "build/build_config.h" #include "media/base/audio_hardware_config.h" #include "media/audio/audio_parameters.h" #include "testing/gtest/include/gtest/gtest.h" @@ -87,4 +88,36 @@ TEST(AudioHardwareConfig, Setters) { EXPECT_EQ(kNewInputChannelLayout, fake_config.GetInputChannelLayout()); } +TEST(AudioHardwareConfig, HighLatencyBufferSizes) { + AudioParameters input_params(AudioParameters::AUDIO_PCM_LOW_LATENCY, + kInputChannelLayout, + kInputSampleRate, + 16, + kOutputBufferSize); + AudioParameters output_params(AudioParameters::AUDIO_PCM_LOW_LATENCY, + kOutputChannelLayout, + 3200, + 16, + 32); + AudioHardwareConfig fake_config(input_params, output_params); + +#if defined(OS_LINUX) + EXPECT_EQ(64, fake_config.GetHighLatencyBufferSize()); + + for (int i = 6400; i <= 204800; i *= 2) { + fake_config.UpdateOutputConfig( + AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY, + kOutputChannelLayout, + i, + 16, + 32)); + EXPECT_EQ(2 * (i / 100), fake_config.GetHighLatencyBufferSize()); + } +#else + // If high latency buffer sizes are not supported, the value should just pass + // through the output buffer size. + EXPECT_EQ(32, fake_config.GetHighLatencyBufferSize()); +#endif +} + } // namespace content diff --git a/media/filters/audio_renderer_impl.cc b/media/filters/audio_renderer_impl.cc index acb43f7..bb279e9 100644 --- a/media/filters/audio_renderer_impl.cc +++ b/media/filters/audio_renderer_impl.cc @@ -278,7 +278,14 @@ void AudioRendererImpl::Initialize(DemuxerStream* stream, buffer_converter_.reset(); } else { // TODO(rileya): Support hardware config changes - audio_parameters_ = hardware_config_->GetOutputConfig(); + const AudioParameters& hw_params = hardware_config_->GetOutputConfig(); + audio_parameters_.Reset(hw_params.format(), + hw_params.channel_layout(), + hw_params.channels(), + hw_params.input_channels(), + hw_params.sample_rate(), + hw_params.bits_per_sample(), + hardware_config_->GetHighLatencyBufferSize()); } audio_buffer_stream_.Initialize( |