#include "media/base/audio_converter.h"
#include <memory>
#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/trace_event/trace_event.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),
initial_frames_delayed_(0),
resampler_frames_delayed_(0),
io_sample_rate_ratio_(input_params.sample_rate() /
static_cast<double>(output_params.sample_rate())),
input_channel_count_(input_params.channels()) {
CHECK(input_params.IsValid());
CHECK(output_params.IsValid());
if (input_params.channel_layout() != output_params.channel_layout() ||
input_params.channels() != output_params.channels()) {
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_ =
std::make_unique<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();
resampler_ = std::make_unique<MultiChannelResampler>(
downmix_early_ ? output_params.channels() : input_params.channels(),
io_sample_rate_ratio_, request_size,
base::BindRepeating(&AudioConverter::ProvideInput,
base::Unretained(this)));
}
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_ = std::make_unique<AudioPullFifo>(
downmix_early_ ? output_params.channels() : input_params.channels(),
chunk_size_,
base::BindRepeating(&AudioConverter::SourceCallback,
base::Unretained(this)));
}
}
AudioConverter::~AudioConverter() = default;
void AudioConverter::AddInput(InputCallback* input) {
DCHECK(!base::Contains(transform_inputs_, input));
transform_inputs_.push_back(input);
}
void AudioConverter::RemoveInput(InputCallback* input) {
DCHECK(base::Contains(transform_inputs_, input));
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::PrimeWithSilence() {
if (resampler_) {
resampler_->PrimeWithSilence();
}
}
int AudioConverter::GetMaxInputFramesRequested(int output_frames_requested) {
return resampler_
? resampler_->GetMaxInputFramesRequested(output_frames_requested)
: output_frames_requested;
}
void AudioConverter::ConvertWithInfo(uint32_t initial_frames_delayed,
const AudioGlitchInfo& glitch_info,
AudioBus* dest) {
TRACE_EVENT("audio", "AudioConverter::Convert", "sample rate ratio",
io_sample_rate_ratio_, "delay (frames)", initial_frames_delayed);
initial_frames_delayed_ = initial_frames_delayed;
glitch_info_accumulator_.Add(glitch_info);
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) {
ConvertWithInfo(0, {}, dest);
}
void AudioConverter::SourceCallback(int fifo_frame_delay, AudioBus* dest) {
TRACE_EVENT("audio", "AudioConverter::SourceCallback", "delay (frames)",
fifo_frame_delay);
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());
uint32_t total_frames_delayed =
std::round(initial_frames_delayed_ * io_sample_rate_ratio_);
if (resampler_) {
total_frames_delayed +=
std::round(resampler_frames_delayed_ * io_sample_rate_ratio_);
}
if (audio_fifo_) {
total_frames_delayed += fifo_frame_delay;
}
AudioBus* const provide_input_dest =
transform_inputs_.size() == 1 ? temp_dest : mixer_input_audio_bus_.get();
AudioGlitchInfo glitch_info = glitch_info_accumulator_.GetAndReset();
for (InputCallback* input : transform_inputs_) {
#ifdef BUILDFLAG(ARKWEB_MEDIA_POLICY)
if (!input || !provide_input_dest) {
LOG(ERROR) << "OhMeida: audio_converter input is null? " << !input
<< "provide_input_dest is null? " << !provide_input_dest;
continue;
}
#endif
const float volume = input->ProvideInput(provide_input_dest,
total_frames_delayed, glitch_info);
if (input == transform_inputs_.front()) {
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_span(i), volume,
temp_dest->channel_span(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_span(i), volume,
temp_dest->channel_span(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) {
TRACE_EVENT1("audio", "AudioConverter::ProvideInput", "delay (frames)",
resampler_frame_delay);
resampler_frames_delayed_ = 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);
}
}