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

Side by Side Diff: content/renderer/media/audio_track_recorder_unittest.cc

Issue 1579693006: MediaRecorder: support sampling rate adaption in AudioTrackRecorder (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: miu@s nit Created 4 years, 10 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
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/audio_track_recorder.h" 5 #include "content/renderer/media/audio_track_recorder.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include "base/macros.h" 9 #include "base/macros.h"
10 #include "base/run_loop.h" 10 #include "base/run_loop.h"
(...skipping 13 matching lines...) Expand all
24 using ::testing::DoAll; 24 using ::testing::DoAll;
25 using ::testing::InSequence; 25 using ::testing::InSequence;
26 using ::testing::Mock; 26 using ::testing::Mock;
27 using ::testing::Return; 27 using ::testing::Return;
28 using ::testing::SaveArg; 28 using ::testing::SaveArg;
29 using ::testing::TestWithParam; 29 using ::testing::TestWithParam;
30 using ::testing::ValuesIn; 30 using ::testing::ValuesIn;
31 31
32 namespace { 32 namespace {
33 33
34 // Input audio format.
35 const media::AudioParameters::Format kDefaultInputFormat =
36 media::AudioParameters::AUDIO_PCM_LOW_LATENCY;
37 const int kDefaultBitsPerSample = 16; 34 const int kDefaultBitsPerSample = 16;
38 const int kDefaultSampleRate = 48000; 35 const int kDefaultSampleRate = 48000;
39 // The |frames_per_buffer| field of AudioParameters is not used by ATR. 36 // The |frames_per_buffer| field of AudioParameters is not used by ATR.
40 const int kIgnoreFramesPerBuffer = 1; 37 const int kIgnoreFramesPerBuffer = 1;
41 const int kOpusMaxBufferDurationMS = 120; 38
39 // The following parameters replicate those in audio_track_recorder.cc, see this
40 // file for explanations.
41 const int kMediaStreamAudioTrackBufferDurationMs = 10;
42 const int kOpusBufferDurationMs = 60;
43 const int kRatioInputToOutputFrames =
44 kOpusBufferDurationMs / kMediaStreamAudioTrackBufferDurationMs;
45
46 const int kFramesPerBuffer = kOpusBufferDurationMs * kDefaultSampleRate / 1000;
42 47
43 } // namespace 48 } // namespace
44 49
45 namespace content { 50 namespace content {
46 51
47 ACTION_P(RunClosure, closure) { 52 ACTION_P(RunClosure, closure) {
48 closure.Run(); 53 closure.Run();
49 } 54 }
50 55
51 struct ATRTestParams { 56 struct ATRTestParams {
52 const media::AudioParameters::Format input_format; 57 const media::AudioParameters::Format input_format;
53 const media::ChannelLayout channel_layout; 58 const media::ChannelLayout channel_layout;
54 const int sample_rate; 59 const int sample_rate;
55 const int bits_per_sample; 60 const int bits_per_sample;
56 }; 61 };
57 62
58 const ATRTestParams kATRTestParams[] = { 63 const ATRTestParams kATRTestParams[] = {
59 // Equivalent to default settings: 64 // Equivalent to default settings:
60 {media::AudioParameters::AUDIO_PCM_LOW_LATENCY, /* input format */ 65 {media::AudioParameters::AUDIO_PCM_LOW_LATENCY, /* input format */
61 media::CHANNEL_LAYOUT_STEREO, /* channel layout */ 66 media::CHANNEL_LAYOUT_STEREO, /* channel layout */
62 kDefaultSampleRate, /* sample rate */ 67 kDefaultSampleRate, /* sample rate */
63 kDefaultBitsPerSample}, /* bits per sample */ 68 kDefaultBitsPerSample}, /* bits per sample */
64 // Change to mono: 69 // Change to mono:
65 {media::AudioParameters::AUDIO_PCM_LOW_LATENCY, media::CHANNEL_LAYOUT_MONO, 70 {media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
66 kDefaultSampleRate, kDefaultBitsPerSample}, 71 media::CHANNEL_LAYOUT_MONO,
72 kDefaultSampleRate,
73 kDefaultBitsPerSample},
67 // Different sampling rate as well: 74 // Different sampling rate as well:
68 {media::AudioParameters::AUDIO_PCM_LOW_LATENCY, media::CHANNEL_LAYOUT_MONO,
69 24000, kDefaultBitsPerSample},
70 {media::AudioParameters::AUDIO_PCM_LOW_LATENCY, 75 {media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
71 media::CHANNEL_LAYOUT_STEREO, 8000, kDefaultBitsPerSample}, 76 media::CHANNEL_LAYOUT_MONO,
77 24000,
78 kDefaultBitsPerSample},
79 {media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
80 media::CHANNEL_LAYOUT_STEREO,
81 8000,
82 kDefaultBitsPerSample},
83 // Using a non-default Opus sampling rate (48, 24, 16, 12, or 8 kHz).
84 {media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
85 media::CHANNEL_LAYOUT_MONO,
86 22050,
87 kDefaultBitsPerSample},
88 {media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
89 media::CHANNEL_LAYOUT_STEREO,
90 44100,
91 kDefaultBitsPerSample},
92 {media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
93 media::CHANNEL_LAYOUT_STEREO,
94 96000,
95 kDefaultBitsPerSample},
72 }; 96 };
73 97
74 class AudioTrackRecorderTest : public TestWithParam<ATRTestParams> { 98 class AudioTrackRecorderTest : public TestWithParam<ATRTestParams> {
75 public: 99 public:
76 // Initialize |first_params_| based on test parameters, and |second_params_| 100 // Initialize |first_params_| based on test parameters, and |second_params_|
77 // to always be the same thing. 101 // to always be the same thing.
78 AudioTrackRecorderTest() 102 AudioTrackRecorderTest()
79 : first_params_(GetParam().input_format, 103 : first_params_(GetParam().input_format,
80 GetParam().channel_layout, 104 GetParam().channel_layout,
81 GetParam().sample_rate, 105 GetParam().sample_rate,
82 GetParam().bits_per_sample, 106 GetParam().bits_per_sample,
83 kIgnoreFramesPerBuffer), 107 kIgnoreFramesPerBuffer),
84 second_params_(kDefaultInputFormat, 108 second_params_(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
85 media::CHANNEL_LAYOUT_STEREO, 109 media::CHANNEL_LAYOUT_STEREO,
86 kDefaultSampleRate, 110 kDefaultSampleRate,
87 kDefaultBitsPerSample, 111 kDefaultBitsPerSample,
88 kIgnoreFramesPerBuffer), 112 kIgnoreFramesPerBuffer),
89 first_source_(first_params_.channels(), /* # channels */ 113 first_source_(first_params_.channels(), /* # channels */
90 440, /* frequency */ 114 440, /* frequency */
91 first_params_.sample_rate()), /* sample rate */ 115 first_params_.sample_rate()), /* sample rate */
92 second_source_(second_params_.channels(), 116 second_source_(second_params_.channels(),
93 440, 117 440,
94 second_params_.sample_rate()), 118 second_params_.sample_rate()),
95 opus_decoder_(nullptr) { 119 opus_decoder_(nullptr) {
96 ResetDecoder(first_params_); 120 ResetDecoder(first_params_);
97 PrepareBlinkTrack(); 121 PrepareBlinkTrack();
98 audio_track_recorder_.reset(new AudioTrackRecorder( 122 audio_track_recorder_.reset(new AudioTrackRecorder(
99 blink_track_, base::Bind(&AudioTrackRecorderTest::OnEncodedAudio, 123 blink_track_, base::Bind(&AudioTrackRecorderTest::OnEncodedAudio,
100 base::Unretained(this)), 124 base::Unretained(this)),
101 0 /* bits_per_second */)); 125 0 /* bits_per_second */));
102 } 126 }
103 127
104 ~AudioTrackRecorderTest() { 128 ~AudioTrackRecorderTest() {
105 opus_decoder_destroy(opus_decoder_); 129 opus_decoder_destroy(opus_decoder_);
106 opus_decoder_ = nullptr; 130 opus_decoder_ = nullptr;
107 audio_track_recorder_.reset();
108 blink_track_.reset(); 131 blink_track_.reset();
109 blink::WebHeap::collectAllGarbageForTesting(); 132 blink::WebHeap::collectAllGarbageForTesting();
133 audio_track_recorder_.reset();
134 // Let the message loop run to finish destroying the recorder properly.
135 base::RunLoop().RunUntilIdle();
110 } 136 }
111 137
112 void ResetDecoder(const media::AudioParameters& params) { 138 void ResetDecoder(const media::AudioParameters& params) {
113 if (opus_decoder_) { 139 if (opus_decoder_) {
114 opus_decoder_destroy(opus_decoder_); 140 opus_decoder_destroy(opus_decoder_);
115 opus_decoder_ = nullptr; 141 opus_decoder_ = nullptr;
116 } 142 }
117 143
118 int error; 144 int error;
119 opus_decoder_ = 145 opus_decoder_ =
120 opus_decoder_create(params.sample_rate(), params.channels(), &error); 146 opus_decoder_create(kDefaultSampleRate, params.channels(), &error);
121 EXPECT_TRUE(error == OPUS_OK && opus_decoder_); 147 EXPECT_TRUE(error == OPUS_OK && opus_decoder_);
122 148
123 max_frames_per_buffer_ = 149 buffer_.reset(new float[kFramesPerBuffer * params.channels()]);
124 kOpusMaxBufferDurationMS * params.sample_rate() / 1000;
125 buffer_.reset(new float[max_frames_per_buffer_ * params.channels()]);
126 } 150 }
127 151
128 scoped_ptr<media::AudioBus> GetFirstSourceAudioBus() { 152 scoped_ptr<media::AudioBus> GetFirstSourceAudioBus() {
129 scoped_ptr<media::AudioBus> bus(media::AudioBus::Create( 153 scoped_ptr<media::AudioBus> bus(media::AudioBus::Create(
130 first_params_.channels(), 154 first_params_.channels(), first_params_.sample_rate() *
131 first_params_.sample_rate() * 155 kMediaStreamAudioTrackBufferDurationMs /
132 audio_track_recorder_->GetOpusBufferDuration( 156 base::Time::kMillisecondsPerSecond));
133 first_params_.sample_rate()) /
134 1000));
135 first_source_.OnMoreData(bus.get(), 0, 0); 157 first_source_.OnMoreData(bus.get(), 0, 0);
136 return bus; 158 return bus;
137 } 159 }
138 scoped_ptr<media::AudioBus> GetSecondSourceAudioBus() { 160 scoped_ptr<media::AudioBus> GetSecondSourceAudioBus() {
139 scoped_ptr<media::AudioBus> bus(media::AudioBus::Create( 161 scoped_ptr<media::AudioBus> bus(media::AudioBus::Create(
140 second_params_.channels(), 162 second_params_.channels(), second_params_.sample_rate() *
141 second_params_.sample_rate() * 163 kMediaStreamAudioTrackBufferDurationMs /
142 audio_track_recorder_->GetOpusBufferDuration( 164 base::Time::kMillisecondsPerSecond));
143 second_params_.sample_rate()) /
144 1000));
145 second_source_.OnMoreData(bus.get(), 0, 0); 165 second_source_.OnMoreData(bus.get(), 0, 0);
146 return bus; 166 return bus;
147 } 167 }
148 168
149 MOCK_METHOD3(DoOnEncodedAudio, 169 MOCK_METHOD3(DoOnEncodedAudio,
150 void(const media::AudioParameters& params, 170 void(const media::AudioParameters& params,
151 std::string encoded_data, 171 std::string encoded_data,
152 base::TimeTicks timestamp)); 172 base::TimeTicks timestamp));
153 173
154 void OnEncodedAudio(const media::AudioParameters& params, 174 void OnEncodedAudio(const media::AudioParameters& params,
155 scoped_ptr<std::string> encoded_data, 175 scoped_ptr<std::string> encoded_data,
156 base::TimeTicks timestamp) { 176 base::TimeTicks timestamp) {
157 EXPECT_TRUE(!encoded_data->empty()); 177 EXPECT_TRUE(!encoded_data->empty());
158
159 // Decode |encoded_data| and check we get the expected number of frames 178 // Decode |encoded_data| and check we get the expected number of frames
160 // per buffer. 179 // per buffer.
161 EXPECT_EQ( 180 EXPECT_EQ(kDefaultSampleRate * kOpusBufferDurationMs / 1000,
162 params.sample_rate() * 181 opus_decode_float(
163 audio_track_recorder_->GetOpusBufferDuration(params.sample_rate()) / 182 opus_decoder_, reinterpret_cast<uint8_t*>(
164 1000, 183 string_as_array(encoded_data.get())),
165 opus_decode_float( 184 encoded_data->size(), buffer_.get(), kFramesPerBuffer, 0));
166 opus_decoder_,
167 reinterpret_cast<uint8_t*>(string_as_array(encoded_data.get())),
168 encoded_data->size(), buffer_.get(), max_frames_per_buffer_, 0));
169 185
170 DoOnEncodedAudio(params, *encoded_data, timestamp); 186 DoOnEncodedAudio(params, *encoded_data, timestamp);
171 } 187 }
172 188
173 const base::MessageLoop message_loop_; 189 const base::MessageLoop message_loop_;
174 190
175 // ATR and WebMediaStreamTrack for fooling it. 191 // ATR and WebMediaStreamTrack for fooling it.
176 scoped_ptr<AudioTrackRecorder> audio_track_recorder_; 192 scoped_ptr<AudioTrackRecorder> audio_track_recorder_;
177 blink::WebMediaStreamTrack blink_track_; 193 blink::WebMediaStreamTrack blink_track_;
178 194
179 // Two different sets of AudioParameters for testing re-init of ATR. 195 // Two different sets of AudioParameters for testing re-init of ATR.
180 const media::AudioParameters first_params_; 196 const media::AudioParameters first_params_;
181 const media::AudioParameters second_params_; 197 const media::AudioParameters second_params_;
182 198
183 // AudioSources for creating AudioBuses. 199 // AudioSources for creating AudioBuses.
184 media::SineWaveAudioSource first_source_; 200 media::SineWaveAudioSource first_source_;
185 media::SineWaveAudioSource second_source_; 201 media::SineWaveAudioSource second_source_;
186 202
187 // Decoder for verifying data was properly encoded. 203 // Decoder for verifying data was properly encoded.
188 OpusDecoder* opus_decoder_; 204 OpusDecoder* opus_decoder_;
189 int max_frames_per_buffer_;
190 scoped_ptr<float[]> buffer_; 205 scoped_ptr<float[]> buffer_;
191 206
192 private: 207 private:
193 // Prepares a blink track of a given MediaStreamType and attaches the native 208 // Prepares a blink track of a given MediaStreamType and attaches the native
194 // track, which can be used to capture audio data and pass it to the producer. 209 // track, which can be used to capture audio data and pass it to the producer.
195 // Adapted from media::WebRTCLocalAudioSourceProviderTest. 210 // Adapted from media::WebRTCLocalAudioSourceProviderTest.
196 void PrepareBlinkTrack() { 211 void PrepareBlinkTrack() {
197 MockMediaConstraintFactory constraint_factory; 212 MockMediaConstraintFactory constraint_factory;
198 scoped_refptr<WebRtcAudioCapturer> capturer( 213 scoped_refptr<WebRtcAudioCapturer> capturer(
199 WebRtcAudioCapturer::CreateCapturer( 214 WebRtcAudioCapturer::CreateCapturer(
(...skipping 16 matching lines...) Expand all
216 DISALLOW_COPY_AND_ASSIGN(AudioTrackRecorderTest); 231 DISALLOW_COPY_AND_ASSIGN(AudioTrackRecorderTest);
217 }; 232 };
218 233
219 TEST_P(AudioTrackRecorderTest, OnData) { 234 TEST_P(AudioTrackRecorderTest, OnData) {
220 InSequence s; 235 InSequence s;
221 base::RunLoop run_loop; 236 base::RunLoop run_loop;
222 base::Closure quit_closure = run_loop.QuitClosure(); 237 base::Closure quit_closure = run_loop.QuitClosure();
223 238
224 // Give ATR initial audio parameters. 239 // Give ATR initial audio parameters.
225 audio_track_recorder_->OnSetFormat(first_params_); 240 audio_track_recorder_->OnSetFormat(first_params_);
241
226 // TODO(ajose): consider adding WillOnce(SaveArg...) and inspecting, as done 242 // TODO(ajose): consider adding WillOnce(SaveArg...) and inspecting, as done
227 // in VTR unittests. http://crbug.com/548856 243 // in VTR unittests. http://crbug.com/548856
228 const base::TimeTicks time1 = base::TimeTicks::Now(); 244 EXPECT_CALL(*this, DoOnEncodedAudio(_, _, _)).Times(1);
229 EXPECT_CALL(*this, DoOnEncodedAudio(_, _, time1)).Times(1); 245 audio_track_recorder_->OnData(*GetFirstSourceAudioBus(),
230 audio_track_recorder_->OnData(*GetFirstSourceAudioBus(), time1); 246 base::TimeTicks::Now());
247 for (int i = 0; i < kRatioInputToOutputFrames - 1; ++i) {
248 audio_track_recorder_->OnData(*GetFirstSourceAudioBus(),
249 base::TimeTicks::Now());
250 }
231 251
232 // Send more audio.
233 const base::TimeTicks time2 = base::TimeTicks::Now();
234 EXPECT_CALL(*this, DoOnEncodedAudio(_, _, _)) 252 EXPECT_CALL(*this, DoOnEncodedAudio(_, _, _))
235 .Times(1) 253 .Times(1)
236 // Only reset the decoder once we've heard back: 254 // Only reset the decoder once we've heard back:
237 .WillOnce(RunClosure(base::Bind(&AudioTrackRecorderTest::ResetDecoder, 255 .WillOnce(RunClosure(base::Bind(&AudioTrackRecorderTest::ResetDecoder,
238 base::Unretained(this), second_params_))); 256 base::Unretained(this), second_params_)));
239 audio_track_recorder_->OnData(*GetFirstSourceAudioBus(), time2); 257 audio_track_recorder_->OnData(*GetFirstSourceAudioBus(),
258 base::TimeTicks::Now());
259 for (int i = 0; i < kRatioInputToOutputFrames - 1; ++i) {
260 audio_track_recorder_->OnData(*GetFirstSourceAudioBus(),
261 base::TimeTicks::Now());
262 }
263
264 // If the amount of samples/10ms buffer is not an integer (e.g. 22050Hz) we
265 // need an extra OnData() to account for the round-off error.
266 if (GetParam().sample_rate % 100) {
267 audio_track_recorder_->OnData(*GetFirstSourceAudioBus(),
268 base::TimeTicks::Now());
269 }
240 270
241 // Give ATR new audio parameters. 271 // Give ATR new audio parameters.
242 audio_track_recorder_->OnSetFormat(second_params_); 272 audio_track_recorder_->OnSetFormat(second_params_);
243 273
244 // Send audio with different params. 274 // Send audio with different params.
245 const base::TimeTicks time3 = base::TimeTicks::Now();
246 EXPECT_CALL(*this, DoOnEncodedAudio(_, _, _)) 275 EXPECT_CALL(*this, DoOnEncodedAudio(_, _, _))
247 .Times(1) 276 .Times(1)
248 .WillOnce(RunClosure(quit_closure)); 277 .WillOnce(RunClosure(quit_closure));
249 audio_track_recorder_->OnData(*GetSecondSourceAudioBus(), time3); 278 audio_track_recorder_->OnData(*GetSecondSourceAudioBus(),
279 base::TimeTicks::Now());
280 for (int i = 0; i < kRatioInputToOutputFrames - 1; ++i) {
281 audio_track_recorder_->OnData(*GetSecondSourceAudioBus(),
282 base::TimeTicks::Now());
283 }
250 284
251 run_loop.Run(); 285 run_loop.Run();
252 Mock::VerifyAndClearExpectations(this); 286 Mock::VerifyAndClearExpectations(this);
253 } 287 }
254 288
255 INSTANTIATE_TEST_CASE_P(, AudioTrackRecorderTest, ValuesIn(kATRTestParams)); 289 INSTANTIATE_TEST_CASE_P(, AudioTrackRecorderTest, ValuesIn(kATRTestParams));
256 290
257 } // namespace content 291 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/media/audio_track_recorder.cc ('k') | content/renderer/media/media_recorder_handler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698