Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / components / audio_modem / audio_recorder_unittest.cc
blob598a5c3a9fba9aa8f33e386f8d1c36f8011d0e1f
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
3 // found in the LICENSE file.
5 #include "components/audio_modem/audio_recorder.h"
7 #include <vector>
9 #include "base/bind.h"
10 #include "base/memory/aligned_memory.h"
11 #include "base/run_loop.h"
12 #include "components/audio_modem/audio_recorder_impl.h"
13 #include "components/audio_modem/public/audio_modem_types.h"
14 #include "components/audio_modem/test/random_samples.h"
15 #include "content/public/test/test_browser_thread_bundle.h"
16 #include "media/audio/audio_manager.h"
17 #include "media/audio/audio_manager_base.h"
18 #include "media/base/audio_bus.h"
19 #include "testing/gtest/include/gtest/gtest.h"
21 namespace {
23 const size_t kSomeNumber = 0x9999;
25 class TestAudioInputStream : public media::AudioInputStream {
26 public:
27 TestAudioInputStream(const media::AudioParameters& params,
28 const std::vector<float*> channel_data,
29 size_t samples)
30 : callback_(nullptr), params_(params) {
31 buffer_ = media::AudioBus::CreateWrapper(2);
32 for (size_t i = 0; i < channel_data.size(); ++i)
33 buffer_->SetChannelData(i, channel_data[i]);
34 buffer_->set_frames(samples);
37 ~TestAudioInputStream() override {}
39 bool Open() override { return true; }
40 void Start(AudioInputCallback* callback) override {
41 DCHECK(callback);
42 callback_ = callback;
43 media::AudioManager::Get()->GetTaskRunner()->PostTask(
44 FROM_HERE,
45 base::Bind(&TestAudioInputStream::SimulateRecording,
46 base::Unretained(this)));
48 void Stop() override {}
49 void Close() override {}
50 double GetMaxVolume() override { return 1.0; }
51 void SetVolume(double volume) override {}
52 double GetVolume() override { return 1.0; }
53 bool SetAutomaticGainControl(bool enabled) override { return false; }
54 bool GetAutomaticGainControl() override { return true; }
55 bool IsMuted() override { return false; }
57 private:
58 void SimulateRecording() {
59 const int fpb = params_.frames_per_buffer();
60 for (int i = 0; i < buffer_->frames() / fpb; ++i) {
61 scoped_ptr<media::AudioBus> source = media::AudioBus::Create(2, fpb);
62 buffer_->CopyPartialFramesTo(i * fpb, fpb, 0, source.get());
63 callback_->OnData(this, source.get(), fpb, 1.0);
67 AudioInputCallback* callback_;
68 media::AudioParameters params_;
69 scoped_ptr<media::AudioBus> buffer_;
71 DISALLOW_COPY_AND_ASSIGN(TestAudioInputStream);
74 } // namespace
76 namespace audio_modem {
78 class AudioRecorderTest : public testing::Test {
79 public:
80 AudioRecorderTest() : total_samples_(0), recorder_(nullptr) {
81 if (!media::AudioManager::Get())
82 media::AudioManager::CreateForTesting();
85 ~AudioRecorderTest() override {
86 DeleteRecorder();
87 for (size_t i = 0; i < channel_data_.size(); ++i)
88 base::AlignedFree(channel_data_[i]);
91 void CreateSimpleRecorder() {
92 // If we have input devices, we'll create a recorder which uses a real
93 // input stream, if not, we'll create a recorder which uses our mock input
94 // stream.
95 if (media::AudioManager::Get()->HasAudioInputDevices()) {
96 DeleteRecorder();
97 recorder_ = new AudioRecorderImpl();
98 recorder_->Initialize(base::Bind(&AudioRecorderTest::DecodeSamples,
99 base::Unretained(this)));
100 } else {
101 CreateRecorder(kSomeNumber);
105 void CreateRecorder(size_t samples) {
106 DeleteRecorder();
108 params_ = media::AudioManager::Get()->GetInputStreamParameters(
109 media::AudioManagerBase::kDefaultDeviceId);
111 channel_data_.clear();
112 channel_data_.push_back(GenerateSamples(0x1337, samples));
113 channel_data_.push_back(GenerateSamples(0x7331, samples));
115 total_samples_ = samples;
117 recorder_ = new AudioRecorderImpl();
118 recorder_->set_input_stream_for_testing(
119 new TestAudioInputStream(params_, channel_data_, samples));
120 recorder_->set_params_for_testing(new media::AudioParameters(params_));
121 recorder_->Initialize(
122 base::Bind(&AudioRecorderTest::DecodeSamples, base::Unretained(this)));
125 void DeleteRecorder() {
126 if (!recorder_)
127 return;
128 recorder_->Finalize();
129 recorder_ = nullptr;
132 void RecordAndVerifySamples() {
133 received_samples_.clear();
134 run_loop_.reset(new base::RunLoop());
135 recorder_->Record();
136 run_loop_->Run();
139 void DecodeSamples(const std::string& samples) {
140 received_samples_ += samples;
141 // We expect one less decode than our total samples would ideally have
142 // triggered since we process data in 4k chunks. So our sample processing
143 // will never rarely be perfectly aligned with 0.5s worth of samples, hence
144 // we will almost always run with a buffer of leftover samples that will
145 // not get sent to this callback since the recorder will be waiting for
146 // more data.
147 const size_t decode_buffer = params_.sample_rate() / 2; // 0.5s
148 const size_t expected_samples =
149 (total_samples_ / decode_buffer - 1) * decode_buffer;
150 const size_t expected_samples_size =
151 expected_samples * sizeof(float) * params_.channels();
152 if (received_samples_.size() == expected_samples_size) {
153 VerifySamples();
154 run_loop_->Quit();
158 void VerifySamples() {
159 int differences = 0;
161 float* buffer_view =
162 reinterpret_cast<float*>(string_as_array(&received_samples_));
163 const int channels = params_.channels();
164 const int frames =
165 received_samples_.size() / sizeof(float) / params_.channels();
166 for (int ch = 0; ch < channels; ++ch) {
167 for (int si = 0, di = ch; si < frames; ++si, di += channels)
168 differences += (buffer_view[di] != channel_data_[ch][si]);
171 ASSERT_EQ(0, differences);
174 protected:
175 float* GenerateSamples(int random_seed, size_t size) {
176 float* samples = static_cast<float*>(base::AlignedAlloc(
177 size * sizeof(float), media::AudioBus::kChannelAlignment));
178 PopulateSamples(0x1337, size, samples);
179 return samples;
181 bool IsRecording() {
182 recorder_->FlushAudioLoopForTesting();
183 return recorder_->is_recording_;
186 std::vector<float*> channel_data_;
187 media::AudioParameters params_;
188 size_t total_samples_;
190 // Deleted by calling Finalize() on the object.
191 AudioRecorderImpl* recorder_;
193 std::string received_samples_;
195 scoped_ptr<base::RunLoop> run_loop_;
196 content::TestBrowserThreadBundle thread_bundle_;
200 // http://crbug.com/463854
201 #if defined(OS_MACOSX)
202 #define MAYBE_BasicRecordAndStop DISABLED_BasicRecordAndStop
203 #else
204 #define MAYBE_BasicRecordAndStop BasicRecordAndStop
205 #endif
207 TEST_F(AudioRecorderTest, MAYBE_BasicRecordAndStop) {
208 CreateSimpleRecorder();
210 recorder_->Record();
211 EXPECT_TRUE(IsRecording());
212 recorder_->Stop();
213 EXPECT_FALSE(IsRecording());
214 recorder_->Record();
216 EXPECT_TRUE(IsRecording());
217 recorder_->Stop();
218 EXPECT_FALSE(IsRecording());
219 recorder_->Record();
221 EXPECT_TRUE(IsRecording());
222 recorder_->Stop();
223 EXPECT_FALSE(IsRecording());
225 DeleteRecorder();
228 // http://crbug.com/460685
229 #if defined(OS_MACOSX)
230 #define MAYBE_OutOfOrderRecordAndStopMultiple \
231 DISABLED_OutOfOrderRecordAndStopMultiple
232 #else
233 #define MAYBE_OutOfOrderRecordAndStopMultiple \
234 OutOfOrderRecordAndStopMultiple
235 #endif
237 TEST_F(AudioRecorderTest, MAYBE_OutOfOrderRecordAndStopMultiple) {
238 CreateSimpleRecorder();
240 recorder_->Stop();
241 recorder_->Stop();
242 recorder_->Stop();
243 EXPECT_FALSE(IsRecording());
245 recorder_->Record();
246 recorder_->Record();
247 EXPECT_TRUE(IsRecording());
249 recorder_->Stop();
250 recorder_->Stop();
251 EXPECT_FALSE(IsRecording());
253 DeleteRecorder();
256 TEST_F(AudioRecorderTest, RecordingEndToEnd) {
257 const int kNumSamples = 48000 * 3;
258 CreateRecorder(kNumSamples);
260 RecordAndVerifySamples();
262 DeleteRecorder();
265 // TODO(rkc): Add tests with recording different sample rates.
267 } // namespace audio_modem