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 | 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 Loading... |
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 Loading... |
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 |
OLD | NEW |