audio_converter.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/base/audio_converter.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <algorithm>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind_helpers.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/base/audio_pull_fifo.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/base/channel_mixer.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/base/multi_channel_resampler.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/base/vector_math.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace media {
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AudioConverter::AudioConverter(const AudioParameters& input_params,
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               const AudioParameters& output_params,
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               bool disable_fifo)
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : downmix_early_(false),
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      resampler_frame_delay_(0),
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      input_channel_count_(input_params.channels()) {
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK(input_params.IsValid());
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK(output_params.IsValid());
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Handle different input and output channel layouts.
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (input_params.channel_layout() != output_params.channel_layout()) {
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DVLOG(1) << "Remixing channel layout from " << input_params.channel_layout()
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             << " to " << output_params.channel_layout() << "; from "
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             << input_params.channels() << " channels to "
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             << output_params.channels() << " channels.";
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    channel_mixer_.reset(new ChannelMixer(input_params, output_params));
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Pare off data as early as we can for efficiency.
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    downmix_early_ = input_params.channels() > output_params.channels();
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (downmix_early_) {
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DVLOG(1) << "Remixing channel layout prior to resampling.";
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // |unmixed_audio_| will be allocated on the fly.
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Instead, if we're not downmixing early we need a temporary AudioBus
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // which matches the input channel count but uses the output frame size
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // since we'll mix into the AudioBus from the output stream.
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      unmixed_audio_ = AudioBus::Create(
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          input_params.channels(), output_params.frames_per_buffer());
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Only resample if necessary since it's expensive.
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (input_params.sample_rate() != output_params.sample_rate()) {
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DVLOG(1) << "Resampling from " << input_params.sample_rate() << " to "
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             << output_params.sample_rate();
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    double io_sample_rate_ratio = input_params.sample_rate() /
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        static_cast<double>(output_params.sample_rate());
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    resampler_.reset(new MultiChannelResampler(
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        downmix_early_ ? output_params.channels() :
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            input_params.channels(),
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        io_sample_rate_ratio, base::Bind(
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            &AudioConverter::ProvideInput, base::Unretained(this))));
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  input_frame_duration_ = base::TimeDelta::FromMicroseconds(
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Time::kMicrosecondsPerSecond /
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      static_cast<double>(input_params.sample_rate()));
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  output_frame_duration_ = base::TimeDelta::FromMicroseconds(
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Time::kMicrosecondsPerSecond /
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      static_cast<double>(output_params.sample_rate()));
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (disable_fifo)
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Since the resampler / output device may want a different buffer size than
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the caller asked for, we need to use a FIFO to ensure that both sides
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // read in chunk sizes they're configured for.
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (resampler_.get() ||
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      input_params.frames_per_buffer() != output_params.frames_per_buffer()) {
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DVLOG(1) << "Rebuffering from " << input_params.frames_per_buffer()
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             << " to " << output_params.frames_per_buffer();
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    audio_fifo_.reset(new AudioPullFifo(
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        downmix_early_ ? output_params.channels() :
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            input_params.channels(),
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        input_params.frames_per_buffer(), base::Bind(
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            &AudioConverter::SourceCallback,
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            base::Unretained(this))));
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AudioConverter::~AudioConverter() {}
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioConverter::AddInput(InputCallback* input) {
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  transform_inputs_.push_back(input);
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioConverter::RemoveInput(InputCallback* input) {
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(std::find(transform_inputs_.begin(), transform_inputs_.end(), input) !=
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         transform_inputs_.end());
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  transform_inputs_.remove(input);
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (transform_inputs_.empty())
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Reset();
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioConverter::Reset() {
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (audio_fifo_)
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    audio_fifo_->Clear();
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (resampler_)
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    resampler_->Flush();
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioConverter::Convert(AudioBus* dest) {
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (transform_inputs_.empty()) {
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    dest->Zero();
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool needs_mixing = channel_mixer_ && !downmix_early_;
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AudioBus* temp_dest = needs_mixing ? unmixed_audio_.get() : dest;
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(temp_dest);
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!resampler_ && !audio_fifo_) {
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SourceCallback(0, temp_dest);
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (resampler_)
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      resampler_->Resample(temp_dest, temp_dest->frames());
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ProvideInput(0, temp_dest);
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (needs_mixing) {
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_EQ(temp_dest->frames(), dest->frames());
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    channel_mixer_->Transform(temp_dest, dest);
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioConverter::SourceCallback(int fifo_frame_delay, AudioBus* dest) {
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool needs_downmix = channel_mixer_ && downmix_early_;
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!mixer_input_audio_bus_ ||
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      mixer_input_audio_bus_->frames() != dest->frames()) {
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    mixer_input_audio_bus_ =
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        AudioBus::Create(input_channel_count_, dest->frames());
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (needs_downmix &&
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (!unmixed_audio_ || unmixed_audio_->frames() != dest->frames())) {
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If we're downmixing early we need a temporary AudioBus which matches
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // the the input channel count and input frame size since we're passing
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // |unmixed_audio_| directly to the |source_callback_|.
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    unmixed_audio_ = AudioBus::Create(input_channel_count_, dest->frames());
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AudioBus* temp_dest = needs_downmix ? unmixed_audio_.get() : dest;
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Sanity check our inputs.
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(temp_dest->frames(), mixer_input_audio_bus_->frames());
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(temp_dest->channels(), mixer_input_audio_bus_->channels());
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Calculate the buffer delay for this callback.
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeDelta buffer_delay;
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (resampler_) {
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    buffer_delay += base::TimeDelta::FromMicroseconds(
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        resampler_frame_delay_ * output_frame_duration_.InMicroseconds());
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (audio_fifo_) {
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    buffer_delay += base::TimeDelta::FromMicroseconds(
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        fifo_frame_delay * input_frame_duration_.InMicroseconds());
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Have each mixer render its data into an output buffer then mix the result.
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (InputCallbackSet::iterator it = transform_inputs_.begin();
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != transform_inputs_.end(); ++it) {
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    InputCallback* input = *it;
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    float volume = input->ProvideInput(
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        mixer_input_audio_bus_.get(), buffer_delay);
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Optimize the most common single input, full volume case.
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (it == transform_inputs_.begin()) {
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (volume == 1.0f) {
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        mixer_input_audio_bus_->CopyTo(temp_dest);
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        continue;
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Zero |temp_dest| otherwise, so we're mixing into a clean buffer.
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      temp_dest->Zero();
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Volume adjust and mix each mixer input into |temp_dest| after rendering.
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (volume > 0) {
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for (int i = 0; i < mixer_input_audio_bus_->channels(); ++i) {
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        vector_math::FMAC(
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            mixer_input_audio_bus_->channel(i), volume,
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            mixer_input_audio_bus_->frames(), temp_dest->channel(i));
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (needs_downmix) {
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_EQ(temp_dest->frames(), dest->frames());
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    channel_mixer_->Transform(temp_dest, dest);
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioConverter::ProvideInput(int resampler_frame_delay, AudioBus* dest) {
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  resampler_frame_delay_ = resampler_frame_delay;
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (audio_fifo_)
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    audio_fifo_->Consume(dest, dest->frames());
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SourceCallback(0, dest);
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace media
213