| 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 |