audio_converter.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4//
5// AudioConverter implementation.  Uses MultiChannelSincResampler for resampling
6// audio, ChannelMixer for channel mixing, and AudioPullFifo for buffering.
7//
8// Delay estimates are provided to InputCallbacks based on the frame delay
9// information reported via the resampler and FIFO units.
10
11#include "media/base/audio_converter.h"
12
13#include <algorithm>
14
15#include "base/bind.h"
16#include "base/bind_helpers.h"
17#include "media/base/audio_bus.h"
18#include "media/base/audio_pull_fifo.h"
19#include "media/base/channel_mixer.h"
20#include "media/base/multi_channel_resampler.h"
21#include "media/base/vector_math.h"
22
23namespace media {
24
25AudioConverter::AudioConverter(const AudioParameters& input_params,
26                               const AudioParameters& output_params,
27                               bool disable_fifo)
28    : downmix_early_(false),
29      resampler_frame_delay_(0),
30      input_channel_count_(input_params.channels()) {
31  CHECK(input_params.IsValid());
32  CHECK(output_params.IsValid());
33
34  // Handle different input and output channel layouts.
35  if (input_params.channel_layout() != output_params.channel_layout()) {
36    DVLOG(1) << "Remixing channel layout from " << input_params.channel_layout()
37             << " to " << output_params.channel_layout() << "; from "
38             << input_params.channels() << " channels to "
39             << output_params.channels() << " channels.";
40    channel_mixer_.reset(new ChannelMixer(input_params, output_params));
41
42    // Pare off data as early as we can for efficiency.
43    downmix_early_ = input_params.channels() > output_params.channels();
44    if (downmix_early_) {
45      DVLOG(1) << "Remixing channel layout prior to resampling.";
46      // |unmixed_audio_| will be allocated on the fly.
47    } else {
48      // Instead, if we're not downmixing early we need a temporary AudioBus
49      // which matches the input channel count but uses the output frame size
50      // since we'll mix into the AudioBus from the output stream.
51      unmixed_audio_ = AudioBus::Create(
52          input_params.channels(), output_params.frames_per_buffer());
53    }
54  }
55
56  // Only resample if necessary since it's expensive.
57  if (input_params.sample_rate() != output_params.sample_rate()) {
58    DVLOG(1) << "Resampling from " << input_params.sample_rate() << " to "
59             << output_params.sample_rate();
60    const double io_sample_rate_ratio = input_params.sample_rate() /
61        static_cast<double>(output_params.sample_rate());
62    const int request_size = disable_fifo ? SincResampler::kDefaultRequestSize :
63        input_params.frames_per_buffer();
64    resampler_.reset(new MultiChannelResampler(
65        downmix_early_ ? output_params.channels() :
66            input_params.channels(),
67        io_sample_rate_ratio, request_size, base::Bind(
68            &AudioConverter::ProvideInput, base::Unretained(this))));
69  }
70
71  input_frame_duration_ = base::TimeDelta::FromMicroseconds(
72      base::Time::kMicrosecondsPerSecond /
73      static_cast<double>(input_params.sample_rate()));
74  output_frame_duration_ = base::TimeDelta::FromMicroseconds(
75      base::Time::kMicrosecondsPerSecond /
76      static_cast<double>(output_params.sample_rate()));
77
78  // The resampler can be configured to work with a specific request size, so a
79  // FIFO is not necessary when resampling.
80  if (disable_fifo || resampler_)
81    return;
82
83  // Since the output device may want a different buffer size than the caller
84  // asked for, we need to use a FIFO to ensure that both sides read in chunk
85  // sizes they're configured for.
86  if (input_params.frames_per_buffer() != output_params.frames_per_buffer()) {
87    DVLOG(1) << "Rebuffering from " << input_params.frames_per_buffer()
88             << " to " << output_params.frames_per_buffer();
89    audio_fifo_.reset(new AudioPullFifo(
90        downmix_early_ ? output_params.channels() :
91            input_params.channels(),
92        input_params.frames_per_buffer(), base::Bind(
93            &AudioConverter::SourceCallback,
94            base::Unretained(this))));
95  }
96}
97
98AudioConverter::~AudioConverter() {}
99
100void AudioConverter::AddInput(InputCallback* input) {
101  DCHECK(std::find(transform_inputs_.begin(), transform_inputs_.end(), input) ==
102         transform_inputs_.end());
103  transform_inputs_.push_back(input);
104}
105
106void AudioConverter::RemoveInput(InputCallback* input) {
107  DCHECK(std::find(transform_inputs_.begin(), transform_inputs_.end(), input) !=
108         transform_inputs_.end());
109  transform_inputs_.remove(input);
110
111  if (transform_inputs_.empty())
112    Reset();
113}
114
115void AudioConverter::Reset() {
116  if (audio_fifo_)
117    audio_fifo_->Clear();
118  if (resampler_)
119    resampler_->Flush();
120}
121
122void AudioConverter::ConvertWithDelay(const base::TimeDelta& initial_delay,
123                                      AudioBus* dest) {
124  initial_delay_ = initial_delay;
125
126  if (transform_inputs_.empty()) {
127    dest->Zero();
128    return;
129  }
130
131  // Determine if channel mixing should be done and if it should be done before
132  // or after resampling.  If it's possible to reduce the channel count prior to
133  // resampling we can save a lot of processing time.  Vice versa, we don't want
134  // to increase the channel count prior to resampling for the same reason.
135  bool needs_mixing = channel_mixer_ && !downmix_early_;
136  AudioBus* temp_dest = needs_mixing ? unmixed_audio_.get() : dest;
137  DCHECK(temp_dest);
138
139  // Figure out which method to call based on whether we're resampling and
140  // rebuffering, just resampling, or just mixing.  We want to avoid any extra
141  // steps when possible since we may be converting audio data in real time.
142  if (!resampler_ && !audio_fifo_) {
143    SourceCallback(0, temp_dest);
144  } else {
145    if (resampler_)
146      resampler_->Resample(temp_dest->frames(), temp_dest);
147    else
148      ProvideInput(0, temp_dest);
149  }
150
151  // Finally upmix the channels if we didn't do so earlier.
152  if (needs_mixing) {
153    DCHECK_EQ(temp_dest->frames(), dest->frames());
154    channel_mixer_->Transform(temp_dest, dest);
155  }
156}
157
158void AudioConverter::Convert(AudioBus* dest) {
159  ConvertWithDelay(base::TimeDelta::FromMilliseconds(0), dest);
160}
161
162void AudioConverter::SourceCallback(int fifo_frame_delay, AudioBus* dest) {
163  bool needs_downmix = channel_mixer_ && downmix_early_;
164
165  if (!mixer_input_audio_bus_ ||
166      mixer_input_audio_bus_->frames() != dest->frames()) {
167    mixer_input_audio_bus_ =
168        AudioBus::Create(input_channel_count_, dest->frames());
169  }
170
171  if (needs_downmix &&
172      (!unmixed_audio_ || unmixed_audio_->frames() != dest->frames())) {
173    // If we're downmixing early we need a temporary AudioBus which matches
174    // the the input channel count and input frame size since we're passing
175    // |unmixed_audio_| directly to the |source_callback_|.
176    unmixed_audio_ = AudioBus::Create(input_channel_count_, dest->frames());
177  }
178
179  AudioBus* temp_dest = needs_downmix ? unmixed_audio_.get() : dest;
180
181  // Sanity check our inputs.
182  DCHECK_EQ(temp_dest->frames(), mixer_input_audio_bus_->frames());
183  DCHECK_EQ(temp_dest->channels(), mixer_input_audio_bus_->channels());
184
185  // Calculate the buffer delay for this callback.
186  base::TimeDelta buffer_delay = initial_delay_;
187  if (resampler_) {
188    buffer_delay += base::TimeDelta::FromMicroseconds(
189        resampler_frame_delay_ * output_frame_duration_.InMicroseconds());
190  }
191  if (audio_fifo_) {
192    buffer_delay += base::TimeDelta::FromMicroseconds(
193        fifo_frame_delay * input_frame_duration_.InMicroseconds());
194  }
195
196  // Have each mixer render its data into an output buffer then mix the result.
197  for (InputCallbackSet::iterator it = transform_inputs_.begin();
198       it != transform_inputs_.end(); ++it) {
199    InputCallback* input = *it;
200
201    float volume = input->ProvideInput(
202        mixer_input_audio_bus_.get(), buffer_delay);
203
204    // Optimize the most common single input, full volume case.
205    if (it == transform_inputs_.begin()) {
206      if (volume == 1.0f) {
207        mixer_input_audio_bus_->CopyTo(temp_dest);
208      } else if (volume > 0) {
209        for (int i = 0; i < mixer_input_audio_bus_->channels(); ++i) {
210          vector_math::FMUL(
211              mixer_input_audio_bus_->channel(i), volume,
212              mixer_input_audio_bus_->frames(), temp_dest->channel(i));
213        }
214      } else {
215        // Zero |temp_dest| otherwise, so we're mixing into a clean buffer.
216        temp_dest->Zero();
217      }
218
219      continue;
220    }
221
222    // Volume adjust and mix each mixer input into |temp_dest| after rendering.
223    if (volume > 0) {
224      for (int i = 0; i < mixer_input_audio_bus_->channels(); ++i) {
225        vector_math::FMAC(
226            mixer_input_audio_bus_->channel(i), volume,
227            mixer_input_audio_bus_->frames(), temp_dest->channel(i));
228      }
229    }
230  }
231
232  if (needs_downmix) {
233    DCHECK_EQ(temp_dest->frames(), dest->frames());
234    channel_mixer_->Transform(temp_dest, dest);
235  }
236}
237
238void AudioConverter::ProvideInput(int resampler_frame_delay, AudioBus* dest) {
239  resampler_frame_delay_ = resampler_frame_delay;
240  if (audio_fifo_)
241    audio_fifo_->Consume(dest, dest->frames());
242  else
243    SourceCallback(0, dest);
244}
245
246}  // namespace media
247