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