| 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 27 matching lines...) Expand all Loading... |
| 38 } // anonymous namespace | 38 } // anonymous namespace |
| 39 | 39 |
| 40 // Nested class encapsulating opus-related encoding details. | 40 // Nested class encapsulating opus-related encoding details. |
| 41 // AudioEncoder is created and destroyed on ATR's main thread (usually the | 41 // AudioEncoder is created and destroyed on ATR's main thread (usually the |
| 42 // main render thread) but otherwise should operate entirely on | 42 // main render thread) but otherwise should operate entirely on |
| 43 // |encoder_thread_|, which is owned by AudioTrackRecorder. Be sure to delete | 43 // |encoder_thread_|, which is owned by AudioTrackRecorder. Be sure to delete |
| 44 // |encoder_thread_| before deleting the AudioEncoder using it. | 44 // |encoder_thread_| before deleting the AudioEncoder using it. |
| 45 class AudioTrackRecorder::AudioEncoder | 45 class AudioTrackRecorder::AudioEncoder |
| 46 : public base::RefCountedThreadSafe<AudioEncoder> { | 46 : public base::RefCountedThreadSafe<AudioEncoder> { |
| 47 public: | 47 public: |
| 48 explicit AudioEncoder(const OnEncodedAudioCB& on_encoded_audio_cb) | 48 AudioEncoder(const OnEncodedAudioCB& on_encoded_audio_cb, |
| 49 : on_encoded_audio_cb_(on_encoded_audio_cb), opus_encoder_(nullptr) { | 49 int32_t bits_per_second); |
| 50 // AudioEncoder is constructed on the thread that ATR lives on, but should | |
| 51 // operate only on the encoder thread after that. Reset | |
| 52 // |encoder_thread_checker_| here, as the next call to CalledOnValidThread() | |
| 53 // will be from the encoder thread. | |
| 54 encoder_thread_checker_.DetachFromThread(); | |
| 55 } | |
| 56 | 50 |
| 57 void OnSetFormat(const media::AudioParameters& params); | 51 void OnSetFormat(const media::AudioParameters& params); |
| 58 | 52 |
| 59 void EncodeAudio(scoped_ptr<media::AudioBus> audio_bus, | 53 void EncodeAudio(scoped_ptr<media::AudioBus> audio_bus, |
| 60 const base::TimeTicks& capture_time); | 54 const base::TimeTicks& capture_time); |
| 61 | 55 |
| 62 private: | 56 private: |
| 63 friend class base::RefCountedThreadSafe<AudioEncoder>; | 57 friend class base::RefCountedThreadSafe<AudioEncoder>; |
| 64 | 58 |
| 65 ~AudioEncoder(); | 59 ~AudioEncoder(); |
| 66 | 60 |
| 67 bool is_initialized() const { return !!opus_encoder_; } | 61 bool is_initialized() const { return !!opus_encoder_; } |
| 68 | 62 |
| 69 void DestroyExistingOpusEncoder(); | 63 void DestroyExistingOpusEncoder(); |
| 70 | 64 |
| 71 void TransferSamplesIntoBuffer(const media::AudioBus* audio_bus, | 65 void TransferSamplesIntoBuffer(const media::AudioBus* audio_bus, |
| 72 int source_offset, | 66 int source_offset, |
| 73 int buffer_fill_offset, | 67 int buffer_fill_offset, |
| 74 int num_samples); | 68 int num_samples); |
| 75 bool EncodeFromFilledBuffer(std::string* out); | 69 bool EncodeFromFilledBuffer(std::string* out); |
| 76 | 70 |
| 77 const OnEncodedAudioCB on_encoded_audio_cb_; | 71 const OnEncodedAudioCB on_encoded_audio_cb_; |
| 78 | 72 |
| 73 // Target bitrate for Opus. If 0, Opus provide automatic bitrate is used. |
| 74 const int32_t bits_per_second_; |
| 75 |
| 79 base::ThreadChecker encoder_thread_checker_; | 76 base::ThreadChecker encoder_thread_checker_; |
| 80 | 77 |
| 81 // In the case where a call to EncodeAudio() cannot completely fill the | 78 // In the case where a call to EncodeAudio() cannot completely fill the |
| 82 // buffer, this points to the position at which to populate data in a later | 79 // buffer, this points to the position at which to populate data in a later |
| 83 // call. | 80 // call. |
| 84 int buffer_fill_end_; | 81 int buffer_fill_end_; |
| 85 | 82 |
| 86 int frames_per_buffer_; | 83 int frames_per_buffer_; |
| 87 | 84 |
| 88 // The duration of one set of frames of encoded audio samples. | 85 // The duration of one set of frames of encoded audio samples. |
| 89 base::TimeDelta buffer_duration_; | 86 base::TimeDelta buffer_duration_; |
| 90 | 87 |
| 91 media::AudioParameters audio_params_; | 88 media::AudioParameters audio_params_; |
| 92 | 89 |
| 93 // Buffer for passing AudioBus data to OpusEncoder. | 90 // Buffer for passing AudioBus data to OpusEncoder. |
| 94 scoped_ptr<float[]> buffer_; | 91 scoped_ptr<float[]> buffer_; |
| 95 | 92 |
| 96 OpusEncoder* opus_encoder_; | 93 OpusEncoder* opus_encoder_; |
| 97 | 94 |
| 98 DISALLOW_COPY_AND_ASSIGN(AudioEncoder); | 95 DISALLOW_COPY_AND_ASSIGN(AudioEncoder); |
| 99 }; | 96 }; |
| 100 | 97 |
| 98 AudioTrackRecorder::AudioEncoder::AudioEncoder( |
| 99 const OnEncodedAudioCB& on_encoded_audio_cb, |
| 100 int32_t bits_per_second) |
| 101 : on_encoded_audio_cb_(on_encoded_audio_cb), |
| 102 bits_per_second_(bits_per_second), |
| 103 opus_encoder_(nullptr) { |
| 104 // AudioEncoder is constructed on the thread that ATR lives on, but should |
| 105 // operate only on the encoder thread after that. Reset |
| 106 // |encoder_thread_checker_| here, as the next call to CalledOnValidThread() |
| 107 // will be from the encoder thread. |
| 108 encoder_thread_checker_.DetachFromThread(); |
| 109 } |
| 110 |
| 101 AudioTrackRecorder::AudioEncoder::~AudioEncoder() { | 111 AudioTrackRecorder::AudioEncoder::~AudioEncoder() { |
| 102 // We don't DCHECK that we're on the encoder thread here, as it should have | 112 // We don't DCHECK that we're on the encoder thread here, as it should have |
| 103 // already been deleted at this point. | 113 // already been deleted at this point. |
| 104 DestroyExistingOpusEncoder(); | 114 DestroyExistingOpusEncoder(); |
| 105 } | 115 } |
| 106 | 116 |
| 107 void AudioTrackRecorder::AudioEncoder::OnSetFormat( | 117 void AudioTrackRecorder::AudioEncoder::OnSetFormat( |
| 108 const media::AudioParameters& params) { | 118 const media::AudioParameters& params) { |
| 109 DCHECK(encoder_thread_checker_.CalledOnValidThread()); | 119 DCHECK(encoder_thread_checker_.CalledOnValidThread()); |
| 110 if (audio_params_.Equals(params)) | 120 if (audio_params_.Equals(params)) |
| 111 return; | 121 return; |
| 112 | 122 |
| 113 DestroyExistingOpusEncoder(); | 123 DestroyExistingOpusEncoder(); |
| 114 | 124 |
| 115 if (!params.IsValid()) { | 125 if (!params.IsValid() || params.channels() > 2) { |
| 116 DLOG(ERROR) << "Invalid audio params: " << params.AsHumanReadableString(); | 126 DLOG(ERROR) << "Invalid audio params: " << params.AsHumanReadableString(); |
| 117 return; | 127 return; |
| 118 } | 128 } |
| 119 | 129 |
| 120 buffer_duration_ = base::TimeDelta::FromMilliseconds( | 130 buffer_duration_ = base::TimeDelta::FromMilliseconds( |
| 121 AudioTrackRecorder::GetOpusBufferDuration(params.sample_rate())); | 131 AudioTrackRecorder::GetOpusBufferDuration(params.sample_rate())); |
| 122 if (buffer_duration_ == base::TimeDelta()) { | 132 if (buffer_duration_ == base::TimeDelta()) { |
| 123 DLOG(ERROR) << "Could not find a valid |buffer_duration| for the given " | 133 DLOG(ERROR) << "Could not find a valid |buffer_duration| for the given " |
| 124 << "sample rate: " << params.sample_rate(); | 134 << "sample rate: " << params.sample_rate(); |
| 125 return; | 135 return; |
| 126 } | 136 } |
| 127 | 137 |
| 128 frames_per_buffer_ = | 138 frames_per_buffer_ = |
| 129 params.sample_rate() * buffer_duration_.InMilliseconds() / 1000; | 139 params.sample_rate() * buffer_duration_.InMilliseconds() / 1000; |
| 130 if (frames_per_buffer_ * params.channels() > MAX_SAMPLES_PER_BUFFER) { | 140 if (frames_per_buffer_ * params.channels() > MAX_SAMPLES_PER_BUFFER) { |
| 131 DLOG(ERROR) << "Invalid |frames_per_buffer_|: " << frames_per_buffer_; | 141 DLOG(ERROR) << "Invalid |frames_per_buffer_|: " << frames_per_buffer_; |
| 132 return; | 142 return; |
| 133 } | 143 } |
| 134 | 144 |
| 135 // Initialize AudioBus buffer for OpusEncoder. | 145 // Initialize AudioBus buffer for OpusEncoder. |
| 136 buffer_fill_end_ = 0; | 146 buffer_fill_end_ = 0; |
| 137 buffer_.reset(new float[params.channels() * frames_per_buffer_]); | 147 buffer_.reset(new float[params.channels() * frames_per_buffer_]); |
| 138 | 148 |
| 139 // Initialize OpusEncoder. | 149 // Initialize OpusEncoder. |
| 150 DCHECK((params.sample_rate() != 48000) || (params.sample_rate() != 24000) || |
| 151 (params.sample_rate() != 16000) || (params.sample_rate() != 12000) || |
| 152 (params.sample_rate() != 8000)) |
| 153 << "Opus supports only sample rates of {48, 24, 16, 12, 8}000, requested " |
| 154 << params.sample_rate(); |
| 140 int opus_result; | 155 int opus_result; |
| 141 opus_encoder_ = opus_encoder_create(params.sample_rate(), params.channels(), | 156 opus_encoder_ = opus_encoder_create(params.sample_rate(), params.channels(), |
| 142 OPUS_APPLICATION_AUDIO, &opus_result); | 157 OPUS_APPLICATION_AUDIO, &opus_result); |
| 143 if (opus_result < 0) { | 158 if (opus_result < 0) { |
| 144 DLOG(ERROR) << "Couldn't init opus encoder: " << opus_strerror(opus_result) | 159 DLOG(ERROR) << "Couldn't init opus encoder: " << opus_strerror(opus_result) |
| 145 << ", sample rate: " << params.sample_rate() | 160 << ", sample rate: " << params.sample_rate() |
| 146 << ", channels: " << params.channels(); | 161 << ", channels: " << params.channels(); |
| 147 return; | 162 return; |
| 148 } | 163 } |
| 149 | 164 |
| 150 // Note: As of 2013-10-31, the encoder in "auto bitrate" mode would use a | 165 // Note: As of 2013-10-31, the encoder in "auto bitrate" mode would use a |
| 151 // variable bitrate up to 102kbps for 2-channel, 48 kHz audio and a 10 ms | 166 // variable bitrate up to 102kbps for 2-channel, 48 kHz audio and a 10 ms |
| 152 // buffer duration. The opus library authors may, of course, adjust this in | 167 // buffer duration. The opus library authors may, of course, adjust this in |
| 153 // later versions. | 168 // later versions. |
| 154 if (opus_encoder_ctl(opus_encoder_, OPUS_SET_BITRATE(OPUS_AUTO)) != OPUS_OK) { | 169 const opus_int32 bitrate = |
| 155 DLOG(ERROR) << "Failed to set opus bitrate."; | 170 (bits_per_second_ > 0) ? bits_per_second_ : OPUS_AUTO; |
| 171 if (opus_encoder_ctl(opus_encoder_, OPUS_SET_BITRATE(bitrate)) != OPUS_OK) { |
| 172 DLOG(ERROR) << "Failed to set opus bitrate: " << bitrate; |
| 156 return; | 173 return; |
| 157 } | 174 } |
| 158 | 175 |
| 159 audio_params_ = params; | 176 audio_params_ = params; |
| 160 } | 177 } |
| 161 | 178 |
| 162 void AudioTrackRecorder::AudioEncoder::EncodeAudio( | 179 void AudioTrackRecorder::AudioEncoder::EncodeAudio( |
| 163 scoped_ptr<media::AudioBus> audio_bus, | 180 scoped_ptr<media::AudioBus> audio_bus, |
| 164 const base::TimeTicks& capture_time) { | 181 const base::TimeTicks& capture_time) { |
| 165 DCHECK(encoder_thread_checker_.CalledOnValidThread()); | 182 DCHECK(encoder_thread_checker_.CalledOnValidThread()); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 243 // If |result| in {0,1}, do nothing; the documentation says that a return | 260 // If |result| in {0,1}, do nothing; the documentation says that a return |
| 244 // value of zero or one means the packet does not need to be transmitted. | 261 // value of zero or one means the packet does not need to be transmitted. |
| 245 // Otherwise, we have an error. | 262 // Otherwise, we have an error. |
| 246 DLOG_IF(ERROR, result < 0) << __FUNCTION__ | 263 DLOG_IF(ERROR, result < 0) << __FUNCTION__ |
| 247 << " failed: " << opus_strerror(result); | 264 << " failed: " << opus_strerror(result); |
| 248 return false; | 265 return false; |
| 249 } | 266 } |
| 250 | 267 |
| 251 AudioTrackRecorder::AudioTrackRecorder( | 268 AudioTrackRecorder::AudioTrackRecorder( |
| 252 const blink::WebMediaStreamTrack& track, | 269 const blink::WebMediaStreamTrack& track, |
| 253 const OnEncodedAudioCB& on_encoded_audio_cb) | 270 const OnEncodedAudioCB& on_encoded_audio_cb, |
| 271 int32_t bits_per_second) |
| 254 : track_(track), | 272 : track_(track), |
| 255 encoder_(new AudioEncoder(media::BindToCurrentLoop(on_encoded_audio_cb))), | 273 encoder_(new AudioEncoder(media::BindToCurrentLoop(on_encoded_audio_cb), |
| 274 bits_per_second)), |
| 256 encoder_thread_("AudioEncoderThread") { | 275 encoder_thread_("AudioEncoderThread") { |
| 257 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 276 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
| 258 DCHECK(!track_.isNull()); | 277 DCHECK(!track_.isNull()); |
| 259 DCHECK(track_.extraData()); | 278 DCHECK(track_.extraData()); |
| 260 | 279 |
| 261 // Start the |encoder_thread_|. From this point on, |encoder_| should work | 280 // Start the |encoder_thread_|. From this point on, |encoder_| should work |
| 262 // only on |encoder_thread_|, as enforced by DCHECKs. | 281 // only on |encoder_thread_|, as enforced by DCHECKs. |
| 263 DCHECK(!encoder_thread_.IsRunning()); | 282 DCHECK(!encoder_thread_.IsRunning()); |
| 264 encoder_thread_.Start(); | 283 encoder_thread_.Start(); |
| 265 | 284 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 309 if (sample_rate * possible_duration % 1000 == 0) { | 328 if (sample_rate * possible_duration % 1000 == 0) { |
| 310 return possible_duration; | 329 return possible_duration; |
| 311 } | 330 } |
| 312 } | 331 } |
| 313 | 332 |
| 314 // Otherwise, couldn't find a good duration. | 333 // Otherwise, couldn't find a good duration. |
| 315 return 0; | 334 return 0; |
| 316 } | 335 } |
| 317 | 336 |
| 318 } // namespace content | 337 } // namespace content |
| OLD | NEW |