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