Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(385)

Side by Side Diff: content/renderer/media_recorder/audio_track_recorder.cc

Issue 2881713002: Reland Replace AudioFifo with a deque of AudioBus in ATR::AudioEncoder (Closed)
Patch Set: Zero out all channels of audio_bus Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/media_recorder/audio_track_recorder.h" 5 #include "content/renderer/media_recorder/audio_track_recorder.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/macros.h" 11 #include "base/macros.h"
12 #include "base/stl_util.h" 12 #include "base/stl_util.h"
13 #include "content/renderer/media/media_stream_audio_track.h" 13 #include "content/renderer/media/media_stream_audio_track.h"
14 #include "media/base/audio_bus.h" 14 #include "media/base/audio_bus.h"
15 #include "media/base/audio_converter.h" 15 #include "media/base/audio_converter.h"
16 #include "media/base/audio_fifo.h"
17 #include "media/base/audio_parameters.h" 16 #include "media/base/audio_parameters.h"
18 #include "media/base/audio_sample_types.h" 17 #include "media/base/audio_sample_types.h"
19 #include "media/base/bind_to_current_loop.h" 18 #include "media/base/bind_to_current_loop.h"
20 #include "third_party/opus/src/include/opus.h" 19 #include "third_party/opus/src/include/opus.h"
21 20
22 // Note that this code follows the Chrome media convention of defining a "frame" 21 // Note that this code follows the Chrome media convention of defining a "frame"
23 // as "one multi-channel sample" as opposed to another common definition meaning 22 // as "one multi-channel sample" as opposed to another common definition meaning
24 // "a chunk of samples". Here this second definition of "frame" is called a 23 // "a chunk of samples". Here this second definition of "frame" is called a
25 // "buffer"; so what might be called "frame duration" is instead "buffer 24 // "buffer"; so what might be called "frame duration" is instead "buffer
26 // duration", and so on. 25 // duration", and so on.
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 base::ThreadChecker encoder_thread_checker_; 119 base::ThreadChecker encoder_thread_checker_;
121 120
122 // Track Audio (ingress) and Opus encoder input parameters, respectively. They 121 // Track Audio (ingress) and Opus encoder input parameters, respectively. They
123 // only differ in their sample_rate() and frames_per_buffer(): output is 122 // only differ in their sample_rate() and frames_per_buffer(): output is
124 // 48ksamples/s and 2880, respectively. 123 // 48ksamples/s and 2880, respectively.
125 media::AudioParameters input_params_; 124 media::AudioParameters input_params_;
126 media::AudioParameters output_params_; 125 media::AudioParameters output_params_;
127 126
128 // Sampling rate adapter between an OpusEncoder supported and the provided. 127 // Sampling rate adapter between an OpusEncoder supported and the provided.
129 std::unique_ptr<media::AudioConverter> converter_; 128 std::unique_ptr<media::AudioConverter> converter_;
130 std::unique_ptr<media::AudioFifo> fifo_; 129 std::deque<std::unique_ptr<media::AudioBus>> audio_bus_queue_;
131 130
132 // Buffer for passing AudioBus data to OpusEncoder. 131 // Buffer for passing AudioBus data to OpusEncoder.
133 std::unique_ptr<float[]> buffer_; 132 std::unique_ptr<float[]> buffer_;
134 133
135 // While |paused_|, AudioBuses are not encoded. 134 // While |paused_|, AudioBuses are not encoded.
136 bool paused_; 135 bool paused_;
137 136
137 int frames_queued_;
138
138 OpusEncoder* opus_encoder_; 139 OpusEncoder* opus_encoder_;
139 140
140 DISALLOW_COPY_AND_ASSIGN(AudioEncoder); 141 DISALLOW_COPY_AND_ASSIGN(AudioEncoder);
141 }; 142 };
142 143
143 AudioTrackRecorder::AudioEncoder::AudioEncoder( 144 AudioTrackRecorder::AudioEncoder::AudioEncoder(
144 const OnEncodedAudioCB& on_encoded_audio_cb, 145 const OnEncodedAudioCB& on_encoded_audio_cb,
145 int32_t bits_per_second) 146 int32_t bits_per_second)
146 : on_encoded_audio_cb_(on_encoded_audio_cb), 147 : on_encoded_audio_cb_(on_encoded_audio_cb),
147 bits_per_second_(bits_per_second), 148 bits_per_second_(bits_per_second),
148 paused_(false), 149 paused_(false),
150 frames_queued_(0),
149 opus_encoder_(nullptr) { 151 opus_encoder_(nullptr) {
150 // AudioEncoder is constructed on the thread that ATR lives on, but should 152 // AudioEncoder is constructed on the thread that ATR lives on, but should
151 // operate only on the encoder thread after that. Reset 153 // operate only on the encoder thread after that. Reset
152 // |encoder_thread_checker_| here, as the next call to CalledOnValidThread() 154 // |encoder_thread_checker_| here, as the next call to CalledOnValidThread()
153 // will be from the encoder thread. 155 // will be from the encoder thread.
154 encoder_thread_checker_.DetachFromThread(); 156 encoder_thread_checker_.DetachFromThread();
155 } 157 }
156 158
157 AudioTrackRecorder::AudioEncoder::~AudioEncoder() { 159 AudioTrackRecorder::AudioEncoder::~AudioEncoder() {
158 // We don't DCHECK that we're on the encoder thread here, as it should have 160 // We don't DCHECK that we're on the encoder thread here, as it should have
159 // already been deleted at this point. 161 // already been deleted at this point.
160 DestroyExistingOpusEncoder(); 162 DestroyExistingOpusEncoder();
161 } 163 }
162 164
163 void AudioTrackRecorder::AudioEncoder::OnSetFormat( 165 void AudioTrackRecorder::AudioEncoder::OnSetFormat(
164 const media::AudioParameters& input_params) { 166 const media::AudioParameters& input_params) {
165 DVLOG(1) << __func__; 167 DVLOG(1) << __func__;
166 DCHECK(encoder_thread_checker_.CalledOnValidThread()); 168 DCHECK(encoder_thread_checker_.CalledOnValidThread());
167 if (input_params_.Equals(input_params)) 169 if (input_params_.Equals(input_params))
168 return; 170 return;
169 171
170 DestroyExistingOpusEncoder(); 172 DestroyExistingOpusEncoder();
171 173
172 if (!input_params.IsValid()) { 174 if (!input_params.IsValid()) {
173 DLOG(ERROR) << "Invalid params: " << input_params.AsHumanReadableString(); 175 DLOG(ERROR) << "Invalid params: " << input_params.AsHumanReadableString();
174 return; 176 return;
175 } 177 }
178
176 input_params_ = input_params; 179 input_params_ = input_params;
177 input_params_.set_frames_per_buffer(input_params_.sample_rate() * 180 input_params_.set_frames_per_buffer(input_params_.sample_rate() *
178 kOpusPreferredBufferDurationMs / 181 kOpusPreferredBufferDurationMs /
179 base::Time::kMillisecondsPerSecond); 182 base::Time::kMillisecondsPerSecond);
180 183
181 // third_party/libopus supports up to 2 channels (see implementation of 184 // third_party/libopus supports up to 2 channels (see implementation of
182 // opus_encoder_create()): force |output_params_| to at most those. 185 // opus_encoder_create()): force |output_params_| to at most those.
183 output_params_ = media::AudioParameters( 186 output_params_ = media::AudioParameters(
184 media::AudioParameters::AUDIO_PCM_LOW_LATENCY, 187 media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
185 media::GuessChannelLayout(std::min(input_params_.channels(), 2)), 188 media::GuessChannelLayout(std::min(input_params_.channels(), 2)),
186 kOpusPreferredSamplingRate, 189 kOpusPreferredSamplingRate,
187 input_params_.bits_per_sample(), 190 input_params_.bits_per_sample(),
188 kOpusPreferredFramesPerBuffer); 191 kOpusPreferredFramesPerBuffer);
189 DVLOG(1) << "|input_params_|:" << input_params_.AsHumanReadableString() 192 DVLOG(1) << "|input_params_|:" << input_params_.AsHumanReadableString()
190 << " -->|output_params_|:" << output_params_.AsHumanReadableString(); 193 << " -->|output_params_|:" << output_params_.AsHumanReadableString();
191 194
192 converter_.reset(new media::AudioConverter(input_params_, output_params_, 195 converter_.reset(new media::AudioConverter(input_params_, output_params_,
193 false /* disable_fifo */)); 196 false /* disable_fifo */));
194 converter_->AddInput(this); 197 converter_->AddInput(this);
195 converter_->PrimeWithSilence(); 198 converter_->PrimeWithSilence();
196 199
197 fifo_.reset(new media::AudioFifo( 200 frames_queued_ = 0;
198 input_params_.channels(), 201 audio_bus_queue_.clear();
199 kMaxNumberOfFifoBuffers * input_params_.frames_per_buffer()));
200 202
201 buffer_.reset(new float[output_params_.channels() * 203 buffer_.reset(new float[output_params_.channels() *
202 output_params_.frames_per_buffer()]); 204 output_params_.frames_per_buffer()]);
203 205
204 // Initialize OpusEncoder. 206 // Initialize OpusEncoder.
205 int opus_result; 207 int opus_result;
206 opus_encoder_ = opus_encoder_create(output_params_.sample_rate(), 208 opus_encoder_ = opus_encoder_create(output_params_.sample_rate(),
207 output_params_.channels(), 209 output_params_.channels(),
208 OPUS_APPLICATION_AUDIO, 210 OPUS_APPLICATION_AUDIO,
209 &opus_result); 211 &opus_result);
(...skipping 20 matching lines...) Expand all
230 std::unique_ptr<media::AudioBus> input_bus, 232 std::unique_ptr<media::AudioBus> input_bus,
231 const base::TimeTicks& capture_time) { 233 const base::TimeTicks& capture_time) {
232 DVLOG(3) << __func__ << ", #frames " << input_bus->frames(); 234 DVLOG(3) << __func__ << ", #frames " << input_bus->frames();
233 DCHECK(encoder_thread_checker_.CalledOnValidThread()); 235 DCHECK(encoder_thread_checker_.CalledOnValidThread());
234 DCHECK_EQ(input_bus->channels(), input_params_.channels()); 236 DCHECK_EQ(input_bus->channels(), input_params_.channels());
235 DCHECK(!capture_time.is_null()); 237 DCHECK(!capture_time.is_null());
236 DCHECK(converter_); 238 DCHECK(converter_);
237 239
238 if (!is_initialized() || paused_) 240 if (!is_initialized() || paused_)
239 return; 241 return;
240 // TODO(mcasas): Consider using a std::deque<std::unique_ptr<AudioBus>> 242
241 // instead of 243 frames_queued_ += input_bus->frames();
242 // an AudioFifo, to avoid copying data needlessly since we know the sizes of 244 audio_bus_queue_.push_back(std::move(input_bus));
243 // both input and output and they are multiples. 245
244 fifo_->Push(input_bus.get()); 246 const int max_frame_limit =
247 kMaxNumberOfFifoBuffers * input_params_.frames_per_buffer();
248 while (frames_queued_ > max_frame_limit) {
249 frames_queued_ -= audio_bus_queue_.front()->frames();
250 audio_bus_queue_.pop_front();
251 }
245 252
246 // Wait to have enough |input_bus|s to guarantee a satisfactory conversion. 253 // Wait to have enough |input_bus|s to guarantee a satisfactory conversion.
247 while (fifo_->frames() >= input_params_.frames_per_buffer()) { 254 while (frames_queued_ >= input_params_.frames_per_buffer()) {
248 std::unique_ptr<media::AudioBus> audio_bus = media::AudioBus::Create( 255 std::unique_ptr<media::AudioBus> audio_bus = media::AudioBus::Create(
249 output_params_.channels(), kOpusPreferredFramesPerBuffer); 256 output_params_.channels(), kOpusPreferredFramesPerBuffer);
250 converter_->Convert(audio_bus.get()); 257 converter_->Convert(audio_bus.get());
251 audio_bus->ToInterleaved<media::Float32SampleTypeTraits>( 258 audio_bus->ToInterleaved<media::Float32SampleTypeTraits>(
252 audio_bus->frames(), buffer_.get()); 259 audio_bus->frames(), buffer_.get());
253 260
254 std::unique_ptr<std::string> encoded_data(new std::string()); 261 std::unique_ptr<std::string> encoded_data(new std::string());
255 if (DoEncode(opus_encoder_, buffer_.get(), kOpusPreferredFramesPerBuffer, 262 if (DoEncode(opus_encoder_, buffer_.get(), kOpusPreferredFramesPerBuffer,
256 encoded_data.get())) { 263 encoded_data.get())) {
257 const base::TimeTicks capture_time_of_first_sample = 264 const base::TimeTicks capture_time_of_first_sample =
258 capture_time - 265 capture_time -
259 base::TimeDelta::FromMicroseconds(fifo_->frames() * 266 base::TimeDelta::FromMicroseconds(frames_queued_ *
260 base::Time::kMicrosecondsPerSecond / 267 base::Time::kMicrosecondsPerSecond /
261 input_params_.sample_rate()); 268 input_params_.sample_rate());
262 on_encoded_audio_cb_.Run(output_params_, std::move(encoded_data), 269 on_encoded_audio_cb_.Run(output_params_, std::move(encoded_data),
263 capture_time_of_first_sample); 270 capture_time_of_first_sample);
264 } 271 }
265 } 272 }
266 } 273 }
267 274
268 double AudioTrackRecorder::AudioEncoder::ProvideInput( 275 double AudioTrackRecorder::AudioEncoder::ProvideInput(
269 media::AudioBus* audio_bus, 276 media::AudioBus* audio_bus,
270 uint32_t frames_delayed) { 277 uint32_t frames_delayed) {
271 fifo_->Consume(audio_bus, 0, audio_bus->frames()); 278 if (audio_bus_queue_.empty()) {
279 audio_bus->Zero();
280 return 0.0;
281 }
282
283 frames_queued_ -= audio_bus->frames();
284 audio_bus_queue_.front()->CopyTo(audio_bus);
285 audio_bus_queue_.pop_front();
272 return 1.0; // Return volume greater than zero to indicate we have more data. 286 return 1.0; // Return volume greater than zero to indicate we have more data.
273 } 287 }
274 288
275 void AudioTrackRecorder::AudioEncoder::DestroyExistingOpusEncoder() { 289 void AudioTrackRecorder::AudioEncoder::DestroyExistingOpusEncoder() {
276 // We don't DCHECK that we're on the encoder thread here, as this could be 290 // We don't DCHECK that we're on the encoder thread here, as this could be
277 // called from the dtor (main thread) or from OnSetFormat() (encoder thread). 291 // called from the dtor (main thread) or from OnSetFormat() (encoder thread).
278 if (opus_encoder_) { 292 if (opus_encoder_) {
279 opus_encoder_destroy(opus_encoder_); 293 opus_encoder_destroy(opus_encoder_);
280 opus_encoder_ = nullptr; 294 opus_encoder_ = nullptr;
281 } 295 }
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
337 } 351 }
338 352
339 void AudioTrackRecorder::Resume() { 353 void AudioTrackRecorder::Resume() {
340 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 354 DCHECK(main_render_thread_checker_.CalledOnValidThread());
341 DCHECK(encoder_); 355 DCHECK(encoder_);
342 encoder_thread_.task_runner()->PostTask( 356 encoder_thread_.task_runner()->PostTask(
343 FROM_HERE, base::Bind(&AudioEncoder::set_paused, encoder_, false)); 357 FROM_HERE, base::Bind(&AudioEncoder::set_paused, encoder_, false));
344 } 358 }
345 359
346 } // namespace content 360 } // namespace content
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698