1 // Copyright 2014 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_buffer_converter.h" 6 7 #include <cmath> 8 9 #include "base/logging.h" 10 #include "media/base/audio_buffer.h" 11 #include "media/base/audio_bus.h" 12 #include "media/base/audio_decoder_config.h" 13 #include "media/base/audio_timestamp_helper.h" 14 #include "media/base/buffers.h" 15 #include "media/base/sinc_resampler.h" 16 #include "media/base/vector_math.h" 17 18 namespace media { 19 20 // Is the config presented by |buffer| a config change from |params|? 21 static bool IsConfigChange(const AudioParameters& params, 22 const scoped_refptr<AudioBuffer>& buffer) { 23 return buffer->sample_rate() != params.sample_rate() || 24 buffer->channel_count() != params.channels() || 25 buffer->channel_layout() != params.channel_layout(); 26 } 27 28 AudioBufferConverter::AudioBufferConverter(const AudioParameters& output_params) 29 : output_params_(output_params), 30 input_params_(output_params), 31 last_input_buffer_offset_(0), 32 input_frames_(0), 33 buffered_input_frames_(0.0), 34 io_sample_rate_ratio_(1.0), 35 timestamp_helper_(output_params_.sample_rate()), 36 is_flushing_(false) {} 37 38 AudioBufferConverter::~AudioBufferConverter() {} 39 40 void AudioBufferConverter::AddInput(const scoped_refptr<AudioBuffer>& buffer) { 41 // On EOS flush any remaining buffered data. 42 if (buffer->end_of_stream()) { 43 Flush(); 44 queued_outputs_.push_back(buffer); 45 return; 46 } 47 48 // We'll need a new |audio_converter_| if there was a config change. 49 if (IsConfigChange(input_params_, buffer)) 50 ResetConverter(buffer); 51 52 // Pass straight through if there's no work to be done. 53 if (!audio_converter_) { 54 queued_outputs_.push_back(buffer); 55 return; 56 } 57 58 if (timestamp_helper_.base_timestamp() == kNoTimestamp()) 59 timestamp_helper_.SetBaseTimestamp(buffer->timestamp()); 60 61 queued_inputs_.push_back(buffer); 62 input_frames_ += buffer->frame_count(); 63 64 ConvertIfPossible(); 65 } 66 67 bool AudioBufferConverter::HasNextBuffer() { return !queued_outputs_.empty(); } 68 69 scoped_refptr<AudioBuffer> AudioBufferConverter::GetNextBuffer() { 70 DCHECK(!queued_outputs_.empty()); 71 scoped_refptr<AudioBuffer> out = queued_outputs_.front(); 72 queued_outputs_.pop_front(); 73 return out; 74 } 75 76 void AudioBufferConverter::Reset() { 77 audio_converter_.reset(); 78 queued_inputs_.clear(); 79 queued_outputs_.clear(); 80 timestamp_helper_.SetBaseTimestamp(kNoTimestamp()); 81 input_params_ = output_params_; 82 input_frames_ = 0; 83 buffered_input_frames_ = 0.0; 84 last_input_buffer_offset_ = 0; 85 } 86 87 void AudioBufferConverter::ResetTimestampState() { 88 Flush(); 89 timestamp_helper_.SetBaseTimestamp(kNoTimestamp()); 90 } 91 92 double AudioBufferConverter::ProvideInput(AudioBus* audio_bus, 93 base::TimeDelta buffer_delay) { 94 DCHECK(is_flushing_ || input_frames_ >= audio_bus->frames()); 95 96 int requested_frames_left = audio_bus->frames(); 97 int dest_index = 0; 98 99 while (requested_frames_left > 0 && !queued_inputs_.empty()) { 100 scoped_refptr<AudioBuffer> input_buffer = queued_inputs_.front(); 101 102 int frames_to_read = 103 std::min(requested_frames_left, 104 input_buffer->frame_count() - last_input_buffer_offset_); 105 input_buffer->ReadFrames( 106 frames_to_read, last_input_buffer_offset_, dest_index, audio_bus); 107 last_input_buffer_offset_ += frames_to_read; 108 109 if (last_input_buffer_offset_ == input_buffer->frame_count()) { 110 // We've consumed all the frames in |input_buffer|. 111 queued_inputs_.pop_front(); 112 last_input_buffer_offset_ = 0; 113 } 114 115 requested_frames_left -= frames_to_read; 116 dest_index += frames_to_read; 117 } 118 119 // If we're flushing, zero any extra space, otherwise we should always have 120 // enough data to completely fulfill the request. 121 if (is_flushing_ && requested_frames_left > 0) { 122 audio_bus->ZeroFramesPartial(audio_bus->frames() - requested_frames_left, 123 requested_frames_left); 124 } else { 125 DCHECK_EQ(requested_frames_left, 0); 126 } 127 128 input_frames_ -= audio_bus->frames() - requested_frames_left; 129 DCHECK_GE(input_frames_, 0); 130 131 buffered_input_frames_ += audio_bus->frames() - requested_frames_left; 132 133 // Full volume. 134 return 1.0; 135 } 136 137 void AudioBufferConverter::ResetConverter( 138 const scoped_refptr<AudioBuffer>& buffer) { 139 Flush(); 140 audio_converter_.reset(); 141 input_params_.Reset( 142 input_params_.format(), 143 buffer->channel_layout(), 144 buffer->channel_count(), 145 buffer->sample_rate(), 146 input_params_.bits_per_sample(), 147 // If resampling is needed and the FIFO disabled, the AudioConverter will 148 // always request SincResampler::kDefaultRequestSize frames. Otherwise it 149 // will use the output frame size. 150 buffer->sample_rate() == output_params_.sample_rate() 151 ? output_params_.frames_per_buffer() 152 : SincResampler::kDefaultRequestSize); 153 154 io_sample_rate_ratio_ = static_cast<double>(input_params_.sample_rate()) / 155 output_params_.sample_rate(); 156 157 // If |buffer| matches |output_params_| we don't need an AudioConverter at 158 // all, and can early-out here. 159 if (!IsConfigChange(output_params_, buffer)) 160 return; 161 162 // Note: The FIFO is disabled to avoid extraneous memcpy(). 163 audio_converter_.reset( 164 new AudioConverter(input_params_, output_params_, true)); 165 audio_converter_->AddInput(this); 166 } 167 168 void AudioBufferConverter::ConvertIfPossible() { 169 DCHECK(audio_converter_); 170 171 int request_frames = 0; 172 173 if (is_flushing_) { 174 // If we're flushing we want to convert *everything* even if this means 175 // we'll have to pad some silence in ProvideInput(). 176 request_frames = 177 ceil((buffered_input_frames_ + input_frames_) / io_sample_rate_ratio_); 178 } else { 179 // How many calls to ProvideInput() we can satisfy completely. 180 int chunks = input_frames_ / input_params_.frames_per_buffer(); 181 182 // How many output frames that corresponds to: 183 request_frames = chunks * audio_converter_->ChunkSize(); 184 } 185 186 if (!request_frames) 187 return; 188 189 scoped_refptr<AudioBuffer> output_buffer = 190 AudioBuffer::CreateBuffer(kSampleFormatPlanarF32, 191 output_params_.channel_layout(), 192 output_params_.channels(), 193 output_params_.sample_rate(), 194 request_frames); 195 scoped_ptr<AudioBus> output_bus = 196 AudioBus::CreateWrapper(output_buffer->channel_count()); 197 198 int frames_remaining = request_frames; 199 200 // The AudioConverter wants requests of a fixed size, so we'll slide an 201 // AudioBus of that size across the |output_buffer|. 202 while (frames_remaining != 0) { 203 // It's important that this is a multiple of AudioBus::kChannelAlignment in 204 // all requests except for the last, otherwise downstream SIMD optimizations 205 // will crash on unaligned data. 206 const int frames_this_iteration = std::min( 207 static_cast<int>(SincResampler::kDefaultRequestSize), frames_remaining); 208 const int offset_into_buffer = 209 output_buffer->frame_count() - frames_remaining; 210 211 // Wrap the portion of the AudioBuffer in an AudioBus so the AudioConverter 212 // can fill it. 213 output_bus->set_frames(frames_this_iteration); 214 for (int ch = 0; ch < output_buffer->channel_count(); ++ch) { 215 output_bus->SetChannelData( 216 ch, 217 reinterpret_cast<float*>(output_buffer->channel_data()[ch]) + 218 offset_into_buffer); 219 } 220 221 // Do the actual conversion. 222 audio_converter_->Convert(output_bus.get()); 223 frames_remaining -= frames_this_iteration; 224 buffered_input_frames_ -= frames_this_iteration * io_sample_rate_ratio_; 225 } 226 227 // Compute the timestamp. 228 output_buffer->set_timestamp(timestamp_helper_.GetTimestamp()); 229 timestamp_helper_.AddFrames(request_frames); 230 231 queued_outputs_.push_back(output_buffer); 232 } 233 234 void AudioBufferConverter::Flush() { 235 if (!audio_converter_) 236 return; 237 is_flushing_ = true; 238 ConvertIfPossible(); 239 is_flushing_ = false; 240 audio_converter_->Reset(); 241 DCHECK_EQ(input_frames_, 0); 242 DCHECK_EQ(last_input_buffer_offset_, 0); 243 DCHECK_LT(buffered_input_frames_, 1.0); 244 DCHECK(queued_inputs_.empty()); 245 buffered_input_frames_ = 0.0; 246 } 247 248 } // namespace media 249