blob: 7c01eee2cfe746d381c35bc019d03d02de5e08d3 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/base/audio_parameters.h"
#include <sstream>
#include "base/check_op.h"
#include "media/base/audio_bus.h"
#include "media/base/channel_layout.h"
#include "media/base/limits.h"
namespace media {
namespace {
int ComputeChannelCount(ChannelLayout channel_layout, int channels) {
if (channel_layout == CHANNEL_LAYOUT_DISCRETE) {
CHECK_NE(0, channels);
return channels;
} else if (channel_layout == CHANNEL_LAYOUT_5_1_4_DOWNMIX && channels != 0) {
// For CHANNEL_LAYOUT_5_1_4_DOWNMIX we can set a custom number of channels,
// but we are not forced to.
return channels;
}
const int calculated_channel_count =
ChannelLayoutToChannelCount(channel_layout);
DCHECK(channel_layout == CHANNEL_LAYOUT_UNSUPPORTED ||
calculated_channel_count == channels);
return calculated_channel_count;
}
} // namespace
static_assert(AudioBus::kChannelAlignment == kParametersAlignment,
"Audio buffer parameters struct alignment not same as AudioBus");
static_assert(sizeof(AudioInputBufferParameters) %
AudioBus::kChannelAlignment ==
0,
"AudioInputBufferParameters not aligned");
static_assert(sizeof(AudioOutputBufferParameters) %
AudioBus::kChannelAlignment ==
0,
"AudioOutputBufferParameters not aligned");
const char* FormatToString(AudioParameters::Format format) {
switch (format) {
case AudioParameters::AUDIO_PCM_LINEAR:
return "PCM_LINEAR";
case AudioParameters::AUDIO_PCM_LOW_LATENCY:
return "PCM_LOW_LATENCY";
case AudioParameters::AUDIO_BITSTREAM_AC3:
return "BITSTREAM_AC3";
case AudioParameters::AUDIO_BITSTREAM_EAC3:
return "BITSTREAM_EAC3";
case AudioParameters::AUDIO_BITSTREAM_DTS:
return "BITSTREAM_DTS";
case AudioParameters::AUDIO_BITSTREAM_DTS_HD:
return "BITSTREAM_DTS_HD";
case AudioParameters::AUDIO_BITSTREAM_DTSX_P2:
return "BITSTREAM_DTSX_P2";
case AudioParameters::AUDIO_BITSTREAM_IEC61937:
return "BITSTREAM_IEC61937";
case AudioParameters::AUDIO_BITSTREAM_DTS_HD_MA:
return "BITSTREAM_DTS_HD_MA";
case AudioParameters::AUDIO_FAKE:
return "FAKE";
}
}
base::CheckedNumeric<uint32_t> ComputeAudioInputBufferSizeChecked(
const AudioParameters& parameters,
uint32_t shared_memory_count) {
base::CheckedNumeric<uint32_t> result = AudioBus::CalculateMemorySize(
parameters.channels(), parameters.frames_per_buffer());
result += sizeof(media::AudioInputBufferParameters);
result *= shared_memory_count;
return result;
}
uint32_t ComputeAudioInputBufferSize(const AudioParameters& parameters,
uint32_t shared_memory_count) {
return ComputeAudioInputBufferSizeChecked(parameters, shared_memory_count)
.ValueOrDie();
}
uint32_t ComputeAudioInputBufferSize(int channels,
int frames,
uint32_t shared_memory_count) {
base::CheckedNumeric<uint32_t> result =
AudioBus::CalculateMemorySize(channels, frames);
result += sizeof(media::AudioInputBufferParameters);
result *= shared_memory_count;
return result.ValueOrDie();
}
base::CheckedNumeric<uint32_t> ComputeAudioOutputBufferSizeChecked(
const AudioParameters& parameters) {
base::CheckedNumeric<uint32_t> result = AudioBus::CalculateMemorySize(
parameters.channels(), parameters.frames_per_buffer());
result += sizeof(media::AudioOutputBufferParameters);
return result;
}
uint32_t ComputeAudioOutputBufferSize(const AudioParameters& parameters) {
return ComputeAudioOutputBufferSize(parameters.channels(),
parameters.frames_per_buffer());
}
uint32_t ComputeAudioOutputBufferSize(int channels, int frames) {
base::CheckedNumeric<uint32_t> result =
AudioBus::CalculateMemorySize(channels, frames);
result += sizeof(media::AudioOutputBufferParameters);
return result.ValueOrDie();
}
ChannelLayoutConfig::ChannelLayoutConfig(const ChannelLayoutConfig& other) =
default;
ChannelLayoutConfig& ChannelLayoutConfig::operator=(
const ChannelLayoutConfig& other) = default;
ChannelLayoutConfig::~ChannelLayoutConfig() = default;
ChannelLayoutConfig::ChannelLayoutConfig()
: ChannelLayoutConfig(
ChannelLayoutConfig::FromLayout<CHANNEL_LAYOUT_NONE>()) {}
ChannelLayoutConfig::ChannelLayoutConfig(ChannelLayout channel_layout,
int channels)
: channel_layout_(channel_layout),
channels_(ComputeChannelCount(channel_layout, channels)) {}
ChannelLayoutConfig ChannelLayoutConfig::Mono() {
return FromLayout<CHANNEL_LAYOUT_MONO>();
}
ChannelLayoutConfig ChannelLayoutConfig::Stereo() {
return FromLayout<CHANNEL_LAYOUT_STEREO>();
}
ChannelLayoutConfig ChannelLayoutConfig::Guess(int channels) {
return ChannelLayoutConfig(GuessChannelLayout(channels), channels);
}
AudioParameters::AudioParameters()
: AudioParameters(AUDIO_PCM_LINEAR,
ChannelLayoutConfig::FromLayout<CHANNEL_LAYOUT_NONE>(),
0,
0) {}
AudioParameters::AudioParameters(Format format,
ChannelLayoutConfig channel_layout_config,
int sample_rate,
int frames_per_buffer)
: latency_tag_(AudioLatency::LATENCY_COUNT) {
Reset(format, channel_layout_config, sample_rate, frames_per_buffer);
}
AudioParameters::AudioParameters(
Format format,
ChannelLayoutConfig channel_layout_config,
int sample_rate,
int frames_per_buffer,
const HardwareCapabilities& hardware_capabilities)
: latency_tag_(AudioLatency::LATENCY_COUNT),
hardware_capabilities_(hardware_capabilities) {
Reset(format, channel_layout_config, sample_rate, frames_per_buffer);
}
AudioParameters::~AudioParameters() = default;
AudioParameters::AudioParameters(const AudioParameters&) = default;
AudioParameters& AudioParameters::operator=(const AudioParameters&) = default;
void AudioParameters::Reset(Format format,
ChannelLayoutConfig channel_layout_config,
int sample_rate,
int frames_per_buffer) {
format_ = format;
channel_layout_config_ = channel_layout_config;
sample_rate_ = sample_rate;
frames_per_buffer_ = frames_per_buffer;
effects_ = NO_EFFECTS;
mic_positions_.clear();
}
bool AudioParameters::IsValid() const {
return (channels() > 0) && (channels() <= media::limits::kMaxChannels) &&
(channel_layout() > CHANNEL_LAYOUT_UNSUPPORTED) &&
(sample_rate_ >= media::limits::kMinSampleRate) &&
(sample_rate_ <= media::limits::kMaxSampleRate) &&
(frames_per_buffer_ > 0) &&
(frames_per_buffer_ <= media::limits::kMaxSamplesPerPacket) &&
(!hardware_capabilities_ ||
((hardware_capabilities_->min_frames_per_buffer >= 0) &&
(hardware_capabilities_->min_frames_per_buffer <=
media::limits::kMaxSamplesPerPacket) &&
(hardware_capabilities_->max_frames_per_buffer >= 0) &&
(hardware_capabilities_->max_frames_per_buffer <=
media::limits::kMaxSamplesPerPacket) &&
(hardware_capabilities_->max_frames_per_buffer >=
hardware_capabilities_->min_frames_per_buffer))) &&
(channel_layout() == CHANNEL_LAYOUT_DISCRETE ||
channel_layout() == CHANNEL_LAYOUT_5_1_4_DOWNMIX ||
channels() == ChannelLayoutToChannelCount(channel_layout()));
}
std::string AudioParameters::AsHumanReadableString() const {
std::ostringstream s;
s << "format: " << FormatToString(format())
<< ", channel_layout: " << channel_layout() << ", channels: " << channels()
<< ", sample_rate: " << sample_rate()
<< ", frames_per_buffer: " << frames_per_buffer()
<< ", effects: " << effects()
<< ", mic_positions: " << PointsToString(mic_positions_);
if (hardware_capabilities_.has_value()) {
s << ", hw_capabilities: min_frames_per_buffer: "
<< hardware_capabilities_->min_frames_per_buffer
<< ", max_frames_per_buffer: "
<< hardware_capabilities_->max_frames_per_buffer
<< ", bitstream_formats:" << hardware_capabilities_->bitstream_formats
<< ", require_encapsulation:"
<< hardware_capabilities_->require_encapsulation;
}
return s.str();
}
int AudioParameters::GetBytesPerBuffer(SampleFormat fmt) const {
return GetBytesPerFrame(fmt) * frames_per_buffer_;
}
int AudioParameters::GetBytesPerFrame(SampleFormat fmt) const {
return channels() * SampleFormatToBytesPerChannel(fmt);
}
double AudioParameters::GetMicrosecondsPerFrame() const {
return static_cast<double>(base::Time::kMicrosecondsPerSecond) / sample_rate_;
}
base::TimeDelta AudioParameters::GetBufferDuration() const {
return base::Microseconds(static_cast<int64_t>(
frames_per_buffer_ * base::Time::kMicrosecondsPerSecond /
static_cast<float>(sample_rate_)));
}
bool AudioParameters::Equals(const AudioParameters& other) const {
return format_ == other.format() && sample_rate_ == other.sample_rate() &&
channel_layout() == other.channel_layout() &&
channels() == other.channels() &&
frames_per_buffer_ == other.frames_per_buffer() &&
effects_ == other.effects() && mic_positions_ == other.mic_positions_;
}
bool AudioParameters::IsBitstreamFormat() const {
switch (format_) {
case AUDIO_BITSTREAM_AC3:
case AUDIO_BITSTREAM_EAC3:
case AUDIO_BITSTREAM_DTS:
case AUDIO_BITSTREAM_DTS_HD:
case AUDIO_BITSTREAM_DTSX_P2:
case AUDIO_BITSTREAM_IEC61937:
return true;
default:
return false;
}
}
bool AudioParameters::IsFormatSupportedByHardware(Format format) const {
return hardware_capabilities_.has_value() &&
(hardware_capabilities_->bitstream_formats & format);
}
void AudioParameters::SetChannelLayoutConfig(ChannelLayout layout,
int channels) {
channel_layout_config_ = {layout, channels};
}
bool AudioParameters::RequireEncapsulation() const {
return hardware_capabilities_.has_value() &&
hardware_capabilities_->require_encapsulation;
}
// static
AudioParameters AudioParameters::UnavailableDeviceParams() {
// Using 10 ms buffer since WebAudioMediaStreamSource::DeliverRebufferedAudio
// deals incorrectly with reference time calculation if output buffer size
// significantly differs from 10 ms used there, see http://crbug/701000.
return media::AudioParameters(
media::AudioParameters::AUDIO_FAKE, ChannelLayoutConfig::Stereo(),
media::AudioParameters::kAudioCDSampleRate,
media::AudioParameters::kAudioCDSampleRate / 100);
}
} // namespace media