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