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