| OLD | NEW |
| 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/audio_track_recorder.h" | 5 #include "content/renderer/media/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" |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 102 public media::AudioConverter::InputCallback { | 102 public media::AudioConverter::InputCallback { |
| 103 public: | 103 public: |
| 104 AudioEncoder(const OnEncodedAudioCB& on_encoded_audio_cb, | 104 AudioEncoder(const OnEncodedAudioCB& on_encoded_audio_cb, |
| 105 int32_t bits_per_second); | 105 int32_t bits_per_second); |
| 106 | 106 |
| 107 void OnSetFormat(const media::AudioParameters& params); | 107 void OnSetFormat(const media::AudioParameters& params); |
| 108 | 108 |
| 109 void EncodeAudio(scoped_ptr<media::AudioBus> audio_bus, | 109 void EncodeAudio(scoped_ptr<media::AudioBus> audio_bus, |
| 110 const base::TimeTicks& capture_time); | 110 const base::TimeTicks& capture_time); |
| 111 | 111 |
| 112 void set_paused(bool paused) { paused_ = paused; } |
| 113 |
| 112 private: | 114 private: |
| 113 friend class base::RefCountedThreadSafe<AudioEncoder>; | 115 friend class base::RefCountedThreadSafe<AudioEncoder>; |
| 114 | |
| 115 ~AudioEncoder() override; | 116 ~AudioEncoder() override; |
| 116 | 117 |
| 117 bool is_initialized() const { return !!opus_encoder_; } | 118 bool is_initialized() const { return !!opus_encoder_; } |
| 118 | 119 |
| 119 // media::AudioConverted::InputCallback implementation. | 120 // media::AudioConverted::InputCallback implementation. |
| 120 double ProvideInput(media::AudioBus* audio_bus, | 121 double ProvideInput(media::AudioBus* audio_bus, |
| 121 base::TimeDelta buffer_delay) override; | 122 base::TimeDelta buffer_delay) override; |
| 122 | 123 |
| 123 void DestroyExistingOpusEncoder(); | 124 void DestroyExistingOpusEncoder(); |
| 124 | 125 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 135 media::AudioParameters input_params_; | 136 media::AudioParameters input_params_; |
| 136 media::AudioParameters output_params_; | 137 media::AudioParameters output_params_; |
| 137 | 138 |
| 138 // Sampling rate adapter between an OpusEncoder supported and the provided. | 139 // Sampling rate adapter between an OpusEncoder supported and the provided. |
| 139 scoped_ptr<media::AudioConverter> converter_; | 140 scoped_ptr<media::AudioConverter> converter_; |
| 140 scoped_ptr<media::AudioFifo> fifo_; | 141 scoped_ptr<media::AudioFifo> fifo_; |
| 141 | 142 |
| 142 // Buffer for passing AudioBus data to OpusEncoder. | 143 // Buffer for passing AudioBus data to OpusEncoder. |
| 143 scoped_ptr<float[]> buffer_; | 144 scoped_ptr<float[]> buffer_; |
| 144 | 145 |
| 146 // While |paused_|, AudioBuses are not encoded. |
| 147 bool paused_; |
| 148 |
| 145 OpusEncoder* opus_encoder_; | 149 OpusEncoder* opus_encoder_; |
| 146 | 150 |
| 147 DISALLOW_COPY_AND_ASSIGN(AudioEncoder); | 151 DISALLOW_COPY_AND_ASSIGN(AudioEncoder); |
| 148 }; | 152 }; |
| 149 | 153 |
| 150 AudioTrackRecorder::AudioEncoder::AudioEncoder( | 154 AudioTrackRecorder::AudioEncoder::AudioEncoder( |
| 151 const OnEncodedAudioCB& on_encoded_audio_cb, | 155 const OnEncodedAudioCB& on_encoded_audio_cb, |
| 152 int32_t bits_per_second) | 156 int32_t bits_per_second) |
| 153 : on_encoded_audio_cb_(on_encoded_audio_cb), | 157 : on_encoded_audio_cb_(on_encoded_audio_cb), |
| 154 bits_per_second_(bits_per_second), | 158 bits_per_second_(bits_per_second), |
| 159 paused_(false), |
| 155 opus_encoder_(nullptr) { | 160 opus_encoder_(nullptr) { |
| 156 // AudioEncoder is constructed on the thread that ATR lives on, but should | 161 // AudioEncoder is constructed on the thread that ATR lives on, but should |
| 157 // operate only on the encoder thread after that. Reset | 162 // operate only on the encoder thread after that. Reset |
| 158 // |encoder_thread_checker_| here, as the next call to CalledOnValidThread() | 163 // |encoder_thread_checker_| here, as the next call to CalledOnValidThread() |
| 159 // will be from the encoder thread. | 164 // will be from the encoder thread. |
| 160 encoder_thread_checker_.DetachFromThread(); | 165 encoder_thread_checker_.DetachFromThread(); |
| 161 } | 166 } |
| 162 | 167 |
| 163 AudioTrackRecorder::AudioEncoder::~AudioEncoder() { | 168 AudioTrackRecorder::AudioEncoder::~AudioEncoder() { |
| 164 // We don't DCHECK that we're on the encoder thread here, as it should have | 169 // We don't DCHECK that we're on the encoder thread here, as it should have |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 234 | 239 |
| 235 void AudioTrackRecorder::AudioEncoder::EncodeAudio( | 240 void AudioTrackRecorder::AudioEncoder::EncodeAudio( |
| 236 scoped_ptr<media::AudioBus> input_bus, | 241 scoped_ptr<media::AudioBus> input_bus, |
| 237 const base::TimeTicks& capture_time) { | 242 const base::TimeTicks& capture_time) { |
| 238 DVLOG(1) << __FUNCTION__ << ", #frames " << input_bus->frames(); | 243 DVLOG(1) << __FUNCTION__ << ", #frames " << input_bus->frames(); |
| 239 DCHECK(encoder_thread_checker_.CalledOnValidThread()); | 244 DCHECK(encoder_thread_checker_.CalledOnValidThread()); |
| 240 DCHECK_EQ(input_bus->channels(), input_params_.channels()); | 245 DCHECK_EQ(input_bus->channels(), input_params_.channels()); |
| 241 DCHECK(!capture_time.is_null()); | 246 DCHECK(!capture_time.is_null()); |
| 242 DCHECK(converter_); | 247 DCHECK(converter_); |
| 243 | 248 |
| 244 if (!is_initialized()) | 249 if (!is_initialized() || paused_) |
| 245 return; | 250 return; |
| 246 // TODO(mcasas): Consider using a std::deque<scoped_ptr<AudioBus>> instead of | 251 // TODO(mcasas): Consider using a std::deque<scoped_ptr<AudioBus>> instead of |
| 247 // an AudioFifo, to avoid copying data needlessly since we know the sizes of | 252 // an AudioFifo, to avoid copying data needlessly since we know the sizes of |
| 248 // both input and output and they are multiples. | 253 // both input and output and they are multiples. |
| 249 fifo_->Push(input_bus.get()); | 254 fifo_->Push(input_bus.get()); |
| 250 | 255 |
| 251 // Wait to have enough |input_bus|s to guarantee a satisfactory conversion. | 256 // Wait to have enough |input_bus|s to guarantee a satisfactory conversion. |
| 252 while (fifo_->frames() >= input_params_.frames_per_buffer()) { | 257 while (fifo_->frames() >= input_params_.frames_per_buffer()) { |
| 253 scoped_ptr<media::AudioBus> audio_bus = media::AudioBus::Create( | 258 scoped_ptr<media::AudioBus> audio_bus = media::AudioBus::Create( |
| 254 output_params_.channels(), kOpusPreferredFramesPerBuffer); | 259 output_params_.channels(), kOpusPreferredFramesPerBuffer); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 271 | 276 |
| 272 double AudioTrackRecorder::AudioEncoder::ProvideInput( | 277 double AudioTrackRecorder::AudioEncoder::ProvideInput( |
| 273 media::AudioBus* audio_bus, | 278 media::AudioBus* audio_bus, |
| 274 base::TimeDelta buffer_delay) { | 279 base::TimeDelta buffer_delay) { |
| 275 fifo_->Consume(audio_bus, 0, audio_bus->frames()); | 280 fifo_->Consume(audio_bus, 0, audio_bus->frames()); |
| 276 return 1.0; // Return volume greater than zero to indicate we have more data. | 281 return 1.0; // Return volume greater than zero to indicate we have more data. |
| 277 } | 282 } |
| 278 | 283 |
| 279 void AudioTrackRecorder::AudioEncoder::DestroyExistingOpusEncoder() { | 284 void AudioTrackRecorder::AudioEncoder::DestroyExistingOpusEncoder() { |
| 280 // We don't DCHECK that we're on the encoder thread here, as this could be | 285 // We don't DCHECK that we're on the encoder thread here, as this could be |
| 281 // called from the dtor (main thread) or from OnSetForamt() (render thread); | 286 // called from the dtor (main thread) or from OnSetFormat() (encoder thread). |
| 282 if (opus_encoder_) { | 287 if (opus_encoder_) { |
| 283 opus_encoder_destroy(opus_encoder_); | 288 opus_encoder_destroy(opus_encoder_); |
| 284 opus_encoder_ = nullptr; | 289 opus_encoder_ = nullptr; |
| 285 } | 290 } |
| 286 } | 291 } |
| 287 | 292 |
| 288 AudioTrackRecorder::AudioTrackRecorder( | 293 AudioTrackRecorder::AudioTrackRecorder( |
| 289 const blink::WebMediaStreamTrack& track, | 294 const blink::WebMediaStreamTrack& track, |
| 290 const OnEncodedAudioCB& on_encoded_audio_cb, | 295 const OnEncodedAudioCB& on_encoded_audio_cb, |
| 291 int32_t bits_per_second) | 296 int32_t bits_per_second) |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 329 | 334 |
| 330 scoped_ptr<media::AudioBus> audio_data = | 335 scoped_ptr<media::AudioBus> audio_data = |
| 331 media::AudioBus::Create(audio_bus.channels(), audio_bus.frames()); | 336 media::AudioBus::Create(audio_bus.channels(), audio_bus.frames()); |
| 332 audio_bus.CopyTo(audio_data.get()); | 337 audio_bus.CopyTo(audio_data.get()); |
| 333 | 338 |
| 334 encoder_thread_.task_runner()->PostTask( | 339 encoder_thread_.task_runner()->PostTask( |
| 335 FROM_HERE, base::Bind(&AudioEncoder::EncodeAudio, encoder_, | 340 FROM_HERE, base::Bind(&AudioEncoder::EncodeAudio, encoder_, |
| 336 base::Passed(&audio_data), capture_time)); | 341 base::Passed(&audio_data), capture_time)); |
| 337 } | 342 } |
| 338 | 343 |
| 344 void AudioTrackRecorder::Pause() { |
| 345 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
| 346 DCHECK(encoder_); |
| 347 encoder_thread_.task_runner()->PostTask( |
| 348 FROM_HERE, base::Bind(&AudioEncoder::set_paused, encoder_, true)); |
| 349 } |
| 350 |
| 351 void AudioTrackRecorder::Resume() { |
| 352 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
| 353 DCHECK(encoder_); |
| 354 encoder_thread_.task_runner()->PostTask( |
| 355 FROM_HERE, base::Bind(&AudioEncoder::set_paused, encoder_, false)); |
| 356 } |
| 357 |
| 339 } // namespace content | 358 } // namespace content |
| OLD | NEW |