ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / components / audio_modem / audio_recorder_unittest.cc
blob0dd089ae469218aa9f9fccf83011eab7034d3e6e
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_;
199 TEST_F(AudioRecorderTest, BasicRecordAndStop) {
200 CreateSimpleRecorder();
202 recorder_->Record();
203 EXPECT_TRUE(IsRecording());
204 recorder_->Stop();
205 EXPECT_FALSE(IsRecording());
206 recorder_->Record();
208 EXPECT_TRUE(IsRecording());
209 recorder_->Stop();
210 EXPECT_FALSE(IsRecording());
211 recorder_->Record();
213 EXPECT_TRUE(IsRecording());
214 recorder_->Stop();
215 EXPECT_FALSE(IsRecording());
217 DeleteRecorder();
220 // http://crbug.com/460685
221 #if defined(OS_MACOSX)
222 #define MAYBE_OutOfOrderRecordAndStopMultiple \
223 DISABLED_OutOfOrderRecordAndStopMultiple
224 #else
225 #define MAYBE_OutOfOrderRecordAndStopMultiple \
226 OutOfOrderRecordAndStopMultiple
227 #endif
229 TEST_F(AudioRecorderTest, MAYBE_OutOfOrderRecordAndStopMultiple) {
230 CreateSimpleRecorder();
232 recorder_->Stop();
233 recorder_->Stop();
234 recorder_->Stop();
235 EXPECT_FALSE(IsRecording());
237 recorder_->Record();
238 recorder_->Record();
239 EXPECT_TRUE(IsRecording());
241 recorder_->Stop();
242 recorder_->Stop();
243 EXPECT_FALSE(IsRecording());
245 DeleteRecorder();
248 TEST_F(AudioRecorderTest, RecordingEndToEnd) {
249 const int kNumSamples = 48000 * 3;
250 CreateRecorder(kNumSamples);
252 RecordAndVerifySamples();
254 DeleteRecorder();
257 // TODO(rkc): Add tests with recording different sample rates.
259 } // namespace audio_modem