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.
5 // AudioConverter implementation. Uses MultiChannelSincResampler for resampling
6 // audio, ChannelMixer for channel mixing, and AudioPullFifo for buffering.
8 // Delay estimates are provided to InputCallbacks based on the frame delay
9 // information reported via the resampler and FIFO units.
11 #include "media/base/audio_converter.h"
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"
25 AudioConverter::AudioConverter(const AudioParameters
& input_params
,
26 const AudioParameters
& output_params
,
28 : chunk_size_(input_params
.frames_per_buffer()),
29 downmix_early_(false),
30 resampler_frame_delay_(0),
31 input_channel_count_(input_params
.channels()) {
32 CHECK(input_params
.IsValid());
33 CHECK(output_params
.IsValid());
35 // Handle different input and output channel layouts.
36 if (input_params
.channel_layout() != output_params
.channel_layout()) {
37 DVLOG(1) << "Remixing channel layout from " << input_params
.channel_layout()
38 << " to " << output_params
.channel_layout() << "; from "
39 << input_params
.channels() << " channels to "
40 << output_params
.channels() << " channels.";
41 channel_mixer_
.reset(new ChannelMixer(input_params
, output_params
));
43 // Pare off data as early as we can for efficiency.
44 downmix_early_
= input_params
.channels() > output_params
.channels();
47 // Only resample if necessary since it's expensive.
48 if (input_params
.sample_rate() != output_params
.sample_rate()) {
49 DVLOG(1) << "Resampling from " << input_params
.sample_rate() << " to "
50 << output_params
.sample_rate();
51 const int request_size
= disable_fifo
? SincResampler::kDefaultRequestSize
:
52 input_params
.frames_per_buffer();
53 const double io_sample_rate_ratio
=
54 input_params
.sample_rate() /
55 static_cast<double>(output_params
.sample_rate());
56 resampler_
.reset(new MultiChannelResampler(
57 downmix_early_
? output_params
.channels() : input_params
.channels(),
60 base::Bind(&AudioConverter::ProvideInput
, base::Unretained(this))));
63 input_frame_duration_
= base::TimeDelta::FromMicroseconds(
64 base::Time::kMicrosecondsPerSecond
/
65 static_cast<double>(input_params
.sample_rate()));
66 output_frame_duration_
= base::TimeDelta::FromMicroseconds(
67 base::Time::kMicrosecondsPerSecond
/
68 static_cast<double>(output_params
.sample_rate()));
70 // The resampler can be configured to work with a specific request size, so a
71 // FIFO is not necessary when resampling.
72 if (disable_fifo
|| resampler_
)
75 // Since the output device may want a different buffer size than the caller
76 // asked for, we need to use a FIFO to ensure that both sides read in chunk
77 // sizes they're configured for.
78 if (input_params
.frames_per_buffer() != output_params
.frames_per_buffer()) {
79 DVLOG(1) << "Rebuffering from " << input_params
.frames_per_buffer()
80 << " to " << output_params
.frames_per_buffer();
81 chunk_size_
= input_params
.frames_per_buffer();
82 audio_fifo_
.reset(new AudioPullFifo(
83 downmix_early_
? output_params
.channels() : input_params
.channels(),
85 base::Bind(&AudioConverter::SourceCallback
, base::Unretained(this))));
89 AudioConverter::~AudioConverter() {}
91 void AudioConverter::AddInput(InputCallback
* input
) {
92 DCHECK(std::find(transform_inputs_
.begin(), transform_inputs_
.end(), input
) ==
93 transform_inputs_
.end());
94 transform_inputs_
.push_back(input
);
97 void AudioConverter::RemoveInput(InputCallback
* input
) {
98 DCHECK(std::find(transform_inputs_
.begin(), transform_inputs_
.end(), input
) !=
99 transform_inputs_
.end());
100 transform_inputs_
.remove(input
);
102 if (transform_inputs_
.empty())
106 void AudioConverter::Reset() {
108 audio_fifo_
->Clear();
113 int AudioConverter::ChunkSize() const {
116 return resampler_
->ChunkSize();
119 void AudioConverter::ConvertWithDelay(const base::TimeDelta
& initial_delay
,
121 initial_delay_
= initial_delay
;
123 if (transform_inputs_
.empty()) {
128 // Determine if channel mixing should be done and if it should be done before
129 // or after resampling. If it's possible to reduce the channel count prior to
130 // resampling we can save a lot of processing time. Vice versa, we don't want
131 // to increase the channel count prior to resampling for the same reason.
132 bool needs_mixing
= channel_mixer_
&& !downmix_early_
;
135 CreateUnmixedAudioIfNecessary(dest
->frames());
137 AudioBus
* temp_dest
= needs_mixing
? unmixed_audio_
.get() : dest
;
140 // Figure out which method to call based on whether we're resampling and
141 // rebuffering, just resampling, or just mixing. We want to avoid any extra
142 // steps when possible since we may be converting audio data in real time.
143 if (!resampler_
&& !audio_fifo_
) {
144 SourceCallback(0, temp_dest
);
147 resampler_
->Resample(temp_dest
->frames(), temp_dest
);
149 ProvideInput(0, temp_dest
);
152 // Finally upmix the channels if we didn't do so earlier.
154 DCHECK_EQ(temp_dest
->frames(), dest
->frames());
155 channel_mixer_
->Transform(temp_dest
, dest
);
159 void AudioConverter::Convert(AudioBus
* dest
) {
160 ConvertWithDelay(base::TimeDelta::FromMilliseconds(0), dest
);
163 void AudioConverter::SourceCallback(int fifo_frame_delay
, AudioBus
* dest
) {
164 const bool needs_downmix
= channel_mixer_
&& downmix_early_
;
166 if (!mixer_input_audio_bus_
||
167 mixer_input_audio_bus_
->frames() != dest
->frames()) {
168 mixer_input_audio_bus_
=
169 AudioBus::Create(input_channel_count_
, dest
->frames());
172 // If we're downmixing early we need a temporary AudioBus which matches
173 // the the input channel count and input frame size since we're passing
174 // |unmixed_audio_| directly to the |source_callback_|.
176 CreateUnmixedAudioIfNecessary(dest
->frames());
178 AudioBus
* const temp_dest
= needs_downmix
? unmixed_audio_
.get() : dest
;
180 // Sanity check our inputs.
181 DCHECK_EQ(temp_dest
->frames(), mixer_input_audio_bus_
->frames());
182 DCHECK_EQ(temp_dest
->channels(), mixer_input_audio_bus_
->channels());
184 // Calculate the buffer delay for this callback.
185 base::TimeDelta buffer_delay
= initial_delay_
;
187 buffer_delay
+= base::TimeDelta::FromMicroseconds(
188 resampler_frame_delay_
* output_frame_duration_
.InMicroseconds());
191 buffer_delay
+= base::TimeDelta::FromMicroseconds(
192 fifo_frame_delay
* input_frame_duration_
.InMicroseconds());
195 // If we only have a single input, avoid an extra copy.
196 AudioBus
* const provide_input_dest
=
197 transform_inputs_
.size() == 1 ? temp_dest
: mixer_input_audio_bus_
.get();
199 // Have each mixer render its data into an output buffer then mix the result.
200 for (InputCallbackSet::iterator it
= transform_inputs_
.begin();
201 it
!= transform_inputs_
.end(); ++it
) {
202 InputCallback
* input
= *it
;
204 const float volume
= input
->ProvideInput(provide_input_dest
, buffer_delay
);
206 // Optimize the most common single input, full volume case.
207 if (it
== transform_inputs_
.begin()) {
208 if (volume
== 1.0f
) {
209 if (temp_dest
!= provide_input_dest
)
210 provide_input_dest
->CopyTo(temp_dest
);
211 } else if (volume
> 0) {
212 for (int i
= 0; i
< provide_input_dest
->channels(); ++i
) {
214 provide_input_dest
->channel(i
), volume
,
215 provide_input_dest
->frames(), temp_dest
->channel(i
));
218 // Zero |temp_dest| otherwise, so we're mixing into a clean buffer.
225 // Volume adjust and mix each mixer input into |temp_dest| after rendering.
227 for (int i
= 0; i
< mixer_input_audio_bus_
->channels(); ++i
) {
229 mixer_input_audio_bus_
->channel(i
), volume
,
230 mixer_input_audio_bus_
->frames(), temp_dest
->channel(i
));
236 DCHECK_EQ(temp_dest
->frames(), dest
->frames());
237 channel_mixer_
->Transform(temp_dest
, dest
);
241 void AudioConverter::ProvideInput(int resampler_frame_delay
, AudioBus
* dest
) {
242 resampler_frame_delay_
= resampler_frame_delay
;
244 audio_fifo_
->Consume(dest
, dest
->frames());
246 SourceCallback(0, dest
);
249 void AudioConverter::CreateUnmixedAudioIfNecessary(int frames
) {
250 if (!unmixed_audio_
|| unmixed_audio_
->frames() != frames
)
251 unmixed_audio_
= AudioBus::Create(input_channel_count_
, frames
);