blob: 5816ad071ba96ca202182cdb86e1e61e2a99f441 [file] [log] [blame]
// 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 <stdint.h>
#include <algorithm>
#include "base/logging.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "media/base/limits.h"
#if defined(OS_ANDROID)
#include "base/android/build_info.h"
#endif
#if defined(OS_MACOSX)
#include "media/base/mac/audio_latency_mac.h"
#endif
namespace media {
namespace {
#if !defined(OS_WIN)
// Taken from "Bit Twiddling Hacks"
// http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
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
} // namespace
// static
bool AudioLatency::IsResamplingPassthroughSupported(LatencyType type) {
#if defined(OS_CHROMEOS)
return true;
#elif defined(OS_ANDROID)
// Only N MR1+ has support for OpenSLES performance modes which allow for
// power efficient playback. Per the Android audio team, we shouldn't waste
// cycles on resampling when using the playback mode. See OpenSLESOutputStream
// for additional implementation details.
return type == LATENCY_PLAYBACK &&
base::android::BuildInfo::GetInstance()->sdk_int() >=
base::android::SDK_VERSION_NOUGAT_MR1;
#else
return false;
#endif
}
// static
int AudioLatency::GetHighLatencyBufferSize(int sample_rate,
int preferred_buffer_size) {
// Empirically, we consider 20ms of samples to be high latency.
const double twenty_ms_size = 2.0 * sample_rate / 100;
#if defined(OS_WIN)
preferred_buffer_size = std::max(preferred_buffer_size, 1);
// Windows doesn't use power of two buffer sizes, so we should always round up
// to the nearest multiple of the output buffer size.
const int high_latency_buffer_size =
std::ceil(twenty_ms_size / preferred_buffer_size) * preferred_buffer_size;
#else
// On other platforms use the nearest higher power of two buffer size. 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.
const int high_latency_buffer_size = RoundUpToPowerOfTwo(twenty_ms_size);
#endif // defined(OS_WIN)
return std::max(preferred_buffer_size, high_latency_buffer_size);
}
// static
int AudioLatency::GetRtcBufferSize(int sample_rate, int hardware_buffer_size) {
// Use native hardware buffer size as default. On Windows, we strive to open
// up using this native hardware buffer size to achieve best
// possible performance and to ensure that no FIFO is needed on the browser
// side to match the client request. That is why there is no #if case for
// Windows below.
int frames_per_buffer = hardware_buffer_size;
// No |hardware_buffer_size| is specified, fall back to 10 ms buffer size.
if (!frames_per_buffer) {
frames_per_buffer = sample_rate / 100;
DVLOG(1) << "Using 10 ms sink output buffer size: " << frames_per_buffer;
return frames_per_buffer;
}
#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_FUCHSIA)
// On Linux, MacOS and Fuchsia, the low level IO implementations on the
// browser side supports all buffer size the clients want. We use the native
// peer connection buffer size (10ms) to achieve best possible performance.
frames_per_buffer = sample_rate / 100;
#elif defined(OS_ANDROID)
// TODO(olka/henrika): This settings are very old, need to be revisited.
int frames_per_10ms = sample_rate / 100;
if (frames_per_buffer < 2 * frames_per_10ms) {
// Examples of low-latency frame sizes and the resulting |buffer_size|:
// Nexus 7 : 240 audio frames => 2*480 = 960
// Nexus 10 : 256 => 2*441 = 882
// Galaxy Nexus: 144 => 2*441 = 882
frames_per_buffer = 2 * frames_per_10ms;
DVLOG(1) << "Low-latency output detected on Android";
}
#endif
DVLOG(1) << "Using sink output buffer size: " << frames_per_buffer;
return frames_per_buffer;
}
// static
int AudioLatency::GetInteractiveBufferSize(int hardware_buffer_size) {
#if defined(OS_ANDROID)
// Always log this because it's relatively hard to get this
// information out.
LOG(INFO) << "audioHardwareBufferSize = " << hardware_buffer_size;
#endif
return hardware_buffer_size;
}
int AudioLatency::GetExactBufferSize(base::TimeDelta duration,
int sample_rate,
int hardware_buffer_size) {
DCHECK_NE(0, hardware_buffer_size);
const int requested_buffer_size = duration.InSecondsF() * sample_rate;
// On OSX and CRAS the preferred buffer size is larger than the minimum,
// however we allow values down to the minimum if requested explicitly.
#if defined(OS_MACOSX)
const int minimum_buffer_size =
GetMinAudioBufferSizeMacOS(limits::kMinAudioBufferSize, sample_rate);
if (requested_buffer_size > limits::kMaxAudioBufferSize) {
// Mac OS is currently the only platform with a max buffer size less than
// kMaxWebAudioBufferSize. Since Mac OS audio hardware can run at
// kMaxAudioBufferSize (currently 4096) and it only makes sense for Web
// Audio to run at multiples of the hardware buffer size, tell Web Audio to
// just use web audio max (8192) if the user requests >4096.
static_assert(
limits::kMaxWebAudioBufferSize % limits::kMaxAudioBufferSize == 0,
"Returning kMaxWebAudioBufferSize here assumes it's a multiple of the "
"hardware buffer size.");
return limits::kMaxWebAudioBufferSize;
}
#elif defined(USE_CRAS)
const int minimum_buffer_size = limits::kMinAudioBufferSize;
static_assert(limits::kMaxAudioBufferSize >= limits::kMaxWebAudioBufferSize,
"Algorithm needs refactoring if kMaxAudioBufferSize for CRAS "
"is lowered.");
#else
const int minimum_buffer_size = hardware_buffer_size;
#endif
// Round requested size up to next multiple of the minimum hardware size. The
// minimum hardware size is one that we know is allowed by the platform audio
// layer and may be smaller than its preferred buffer size (the
// hardware_buffer_size). For platforms where this is supported we know that
// using a buffer size that is a multiple of this minimum is safe.
const int buffer_size = std::ceil(std::max(requested_buffer_size, 1) /
static_cast<double>(minimum_buffer_size)) *
minimum_buffer_size;
// The maximum must also be a multiple of the minimum hardware buffer size in
// case the clamping below is required.
const int maximum_buffer_size =
(limits::kMaxWebAudioBufferSize / minimum_buffer_size) *
minimum_buffer_size;
return std::min(maximum_buffer_size,
std::max(buffer_size, minimum_buffer_size));
}
} // namespace media