This source file includes following definitions.
- input_channel_count_
- AddInput
- RemoveInput
- Reset
- ChunkSize
- ConvertWithDelay
- SourceCallback
- ProvideInput
- CreateUnmixedAudioIfNecessary
#include "media/base/audio_converter.h"
#include <algorithm>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "media/base/audio_bus.h"
#include "media/base/audio_pull_fifo.h"
#include "media/base/channel_mixer.h"
#include "media/base/multi_channel_resampler.h"
#include "media/base/vector_math.h"
namespace media {
AudioConverter::AudioConverter(const AudioParameters& input_params,
const AudioParameters& output_params,
bool disable_fifo)
: chunk_size_(input_params.frames_per_buffer()),
downmix_early_(false),
resampler_frame_delay_(0),
input_channel_count_(input_params.channels()) {
CHECK(input_params.IsValid());
CHECK(output_params.IsValid());
if (input_params.channel_layout() != output_params.channel_layout()) {
DVLOG(1) << "Remixing channel layout from " << input_params.channel_layout()
<< " to " << output_params.channel_layout() << "; from "
<< input_params.channels() << " channels to "
<< output_params.channels() << " channels.";
channel_mixer_.reset(new ChannelMixer(input_params, output_params));
downmix_early_ = input_params.channels() > output_params.channels();
}
if (input_params.sample_rate() != output_params.sample_rate()) {
DVLOG(1) << "Resampling from " << input_params.sample_rate() << " to "
<< output_params.sample_rate();
const int request_size = disable_fifo ? SincResampler::kDefaultRequestSize :
input_params.frames_per_buffer();
const double io_sample_rate_ratio =
input_params.sample_rate() /
static_cast<double>(output_params.sample_rate());
resampler_.reset(new MultiChannelResampler(
downmix_early_ ? output_params.channels() : input_params.channels(),
io_sample_rate_ratio,
request_size,
base::Bind(&AudioConverter::ProvideInput, base::Unretained(this))));
}
input_frame_duration_ = base::TimeDelta::FromMicroseconds(
base::Time::kMicrosecondsPerSecond /
static_cast<double>(input_params.sample_rate()));
output_frame_duration_ = base::TimeDelta::FromMicroseconds(
base::Time::kMicrosecondsPerSecond /
static_cast<double>(output_params.sample_rate()));
if (disable_fifo || resampler_)
return;
if (input_params.frames_per_buffer() != output_params.frames_per_buffer()) {
DVLOG(1) << "Rebuffering from " << input_params.frames_per_buffer()
<< " to " << output_params.frames_per_buffer();
chunk_size_ = input_params.frames_per_buffer();
audio_fifo_.reset(new AudioPullFifo(
downmix_early_ ? output_params.channels() : input_params.channels(),
chunk_size_,
base::Bind(&AudioConverter::SourceCallback, base::Unretained(this))));
}
}
AudioConverter::~AudioConverter() {}
void AudioConverter::AddInput(InputCallback* input) {
DCHECK(std::find(transform_inputs_.begin(), transform_inputs_.end(), input) ==
transform_inputs_.end());
transform_inputs_.push_back(input);
}
void AudioConverter::RemoveInput(InputCallback* input) {
DCHECK(std::find(transform_inputs_.begin(), transform_inputs_.end(), input) !=
transform_inputs_.end());
transform_inputs_.remove(input);
if (transform_inputs_.empty())
Reset();
}
void AudioConverter::Reset() {
if (audio_fifo_)
audio_fifo_->Clear();
if (resampler_)
resampler_->Flush();
}
int AudioConverter::ChunkSize() const {
if (!resampler_)
return chunk_size_;
return resampler_->ChunkSize();
}
void AudioConverter::ConvertWithDelay(const base::TimeDelta& initial_delay,
AudioBus* dest) {
initial_delay_ = initial_delay;
if (transform_inputs_.empty()) {
dest->Zero();
return;
}
bool needs_mixing = channel_mixer_ && !downmix_early_;
if (needs_mixing)
CreateUnmixedAudioIfNecessary(dest->frames());
AudioBus* temp_dest = needs_mixing ? unmixed_audio_.get() : dest;
DCHECK(temp_dest);
if (!resampler_ && !audio_fifo_) {
SourceCallback(0, temp_dest);
} else {
if (resampler_)
resampler_->Resample(temp_dest->frames(), temp_dest);
else
ProvideInput(0, temp_dest);
}
if (needs_mixing) {
DCHECK_EQ(temp_dest->frames(), dest->frames());
channel_mixer_->Transform(temp_dest, dest);
}
}
void AudioConverter::Convert(AudioBus* dest) {
ConvertWithDelay(base::TimeDelta::FromMilliseconds(0), dest);
}
void AudioConverter::SourceCallback(int fifo_frame_delay, AudioBus* dest) {
const bool needs_downmix = channel_mixer_ && downmix_early_;
if (!mixer_input_audio_bus_ ||
mixer_input_audio_bus_->frames() != dest->frames()) {
mixer_input_audio_bus_ =
AudioBus::Create(input_channel_count_, dest->frames());
}
if (needs_downmix)
CreateUnmixedAudioIfNecessary(dest->frames());
AudioBus* const temp_dest = needs_downmix ? unmixed_audio_.get() : dest;
DCHECK_EQ(temp_dest->frames(), mixer_input_audio_bus_->frames());
DCHECK_EQ(temp_dest->channels(), mixer_input_audio_bus_->channels());
base::TimeDelta buffer_delay = initial_delay_;
if (resampler_) {
buffer_delay += base::TimeDelta::FromMicroseconds(
resampler_frame_delay_ * output_frame_duration_.InMicroseconds());
}
if (audio_fifo_) {
buffer_delay += base::TimeDelta::FromMicroseconds(
fifo_frame_delay * input_frame_duration_.InMicroseconds());
}
AudioBus* const provide_input_dest =
transform_inputs_.size() == 1 ? temp_dest : mixer_input_audio_bus_.get();
for (InputCallbackSet::iterator it = transform_inputs_.begin();
it != transform_inputs_.end(); ++it) {
InputCallback* input = *it;
const float volume = input->ProvideInput(provide_input_dest, buffer_delay);
if (it == transform_inputs_.begin()) {
if (volume == 1.0f) {
if (temp_dest != provide_input_dest)
provide_input_dest->CopyTo(temp_dest);
} else if (volume > 0) {
for (int i = 0; i < provide_input_dest->channels(); ++i) {
vector_math::FMUL(
provide_input_dest->channel(i), volume,
provide_input_dest->frames(), temp_dest->channel(i));
}
} else {
temp_dest->Zero();
}
continue;
}
if (volume > 0) {
for (int i = 0; i < mixer_input_audio_bus_->channels(); ++i) {
vector_math::FMAC(
mixer_input_audio_bus_->channel(i), volume,
mixer_input_audio_bus_->frames(), temp_dest->channel(i));
}
}
}
if (needs_downmix) {
DCHECK_EQ(temp_dest->frames(), dest->frames());
channel_mixer_->Transform(temp_dest, dest);
}
}
void AudioConverter::ProvideInput(int resampler_frame_delay, AudioBus* dest) {
resampler_frame_delay_ = resampler_frame_delay;
if (audio_fifo_)
audio_fifo_->Consume(dest, dest->frames());
else
SourceCallback(0, dest);
}
void AudioConverter::CreateUnmixedAudioIfNecessary(int frames) {
if (!unmixed_audio_ || unmixed_audio_->frames() != frames)
unmixed_audio_ = AudioBus::Create(input_channel_count_, frames);
}
}