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

Side by Side Diff: components/copresence/mediums/audio/audio_recorder_unittest.cc

Issue 419073002: Add the copresence DirectiveHandler. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: review comments Created 6 years, 4 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2014 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.
4
5 #include "components/copresence/mediums/audio/audio_recorder.h"
6
7 #include <cstdlib>
8
9 #include "base/bind.h"
10 #include "base/memory/aligned_memory.h"
11 #include "base/run_loop.h"
12 #include "components/copresence/common/copresence_constants.h"
13 #include "content/public/test/test_browser_thread_bundle.h"
14 #include "media/audio/audio_manager.h"
15 #include "media/audio/audio_manager_base.h"
16 #include "media/base/audio_bus.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18
19 namespace {
20
21 class TestAudioInputStream : public media::AudioInputStream {
22 public:
23 TestAudioInputStream(const media::AudioParameters& params,
24 const std::vector<float*> channel_data,
25 size_t samples)
26 : callback_(NULL), params_(params) {
27 buffer_ = media::AudioBus::CreateWrapper(2);
28 for (size_t i = 0; i < channel_data.size(); ++i)
29 buffer_->SetChannelData(i, channel_data[i]);
30 buffer_->set_frames(samples);
31 }
32
33 virtual ~TestAudioInputStream() {}
34
35 virtual bool Open() OVERRIDE { return true; }
36 virtual void Start(AudioInputCallback* callback) OVERRIDE {
37 DCHECK(callback);
38 callback_ = callback;
39 media::AudioManager::Get()->GetTaskRunner()->PostTask(
40 FROM_HERE,
41 base::Bind(&TestAudioInputStream::SimulateRecording,
42 base::Unretained(this)));
43 }
44 virtual void Stop() OVERRIDE {}
45 virtual void Close() OVERRIDE {}
46 virtual double GetMaxVolume() OVERRIDE { return 1.0; }
47 virtual void SetVolume(double volume) OVERRIDE {}
48 virtual double GetVolume() OVERRIDE { return 1.0; }
49 virtual void SetAutomaticGainControl(bool enabled) OVERRIDE {}
50 virtual bool GetAutomaticGainControl() OVERRIDE { return true; }
51
52 private:
53 void SimulateRecording() {
54 const int fpb = params_.frames_per_buffer();
55 for (int i = 0; i < buffer_->frames() / fpb; ++i) {
56 scoped_ptr<media::AudioBus> source = media::AudioBus::Create(2, fpb);
57 buffer_->CopyPartialFramesTo(i * fpb, fpb, 0, source.get());
58 callback_->OnData(this, source.get(), fpb, 1.0);
59 }
60 }
61
62 AudioInputCallback* callback_;
63 media::AudioParameters params_;
64 scoped_ptr<media::AudioBus> buffer_;
65
66 DISALLOW_COPY_AND_ASSIGN(TestAudioInputStream);
67 };
68
69 } // namespace
70
71 namespace copresence {
72
73 class AudioRecorderTest : public testing::Test {
74 public:
75 AudioRecorderTest() : total_samples_(0), recorder_(NULL) {
76 if (!media::AudioManager::Get())
77 media::AudioManager::CreateForTesting();
78 }
79
80 virtual ~AudioRecorderTest() {
81 DeleteRecorder();
82 for (size_t i = 0; i < channel_data_.size(); ++i)
83 base::AlignedFree(channel_data_[i]);
84 }
85
86 void CreateSimpleRecorder() {
87 DeleteRecorder();
88 recorder_ = new AudioRecorder(
89 base::Bind(&AudioRecorderTest::DecodeSamples, base::Unretained(this)),
90 NULL,
91 make_scoped_ptr<media::AudioParameters>(NULL));
92 }
93
94 void CreateRecorder(size_t channels,
95 size_t sample_rate,
96 size_t bits_per_sample,
97 size_t samples) {
98 DeleteRecorder();
99 params_.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
100 kDefaultChannelLayout,
101 channels,
102 2,
103 sample_rate,
104 bits_per_sample,
105 4096);
106
107 channel_data_.clear();
108 channel_data_.push_back(GenerateSamples(0x1337, samples));
109 channel_data_.push_back(GenerateSamples(0x7331, samples));
110
111 total_samples_ = samples;
112
113 recorder_ = new AudioRecorder(
114 base::Bind(&AudioRecorderTest::DecodeSamples, base::Unretained(this)),
115 new TestAudioInputStream(params_, channel_data_, samples),
116 make_scoped_ptr(new media::AudioParameters(params_)));
117 }
118
119 void DeleteRecorder() {
120 if (!recorder_)
121 return;
122 recorder_->Finalize();
123 recorder_ = NULL;
124 }
125
126 void RecordAndVerifySamples() {
127 received_samples_.clear();
128 run_loop_.reset(new base::RunLoop());
129 recorder_->Record();
130 run_loop_->Run();
131 }
132
133 void DecodeSamples(const std::string& samples) {
134 received_samples_ += samples;
135 // We expect one less decode than our total samples would ideally have
136 // triggered since we process data in 4k chunks. So our sample processing
137 // will never rarely be perfectly aligned with 0.5s worth of samples, hence
138 // we will almost always run with a buffer of leftover samples that will
139 // not get sent to this callback since the recorder will be waiting for
140 // more data.
141 const size_t decode_buffer = params_.sample_rate() / 2; // 0.5s
142 const size_t expected_samples =
143 (total_samples_ / decode_buffer - 1) * decode_buffer;
144 const size_t expected_samples_size =
145 expected_samples * sizeof(float) * params_.channels();
146 if (received_samples_.size() == expected_samples_size) {
147 VerifySamples();
148 run_loop_->Quit();
149 }
150 }
151
152 void VerifySamples() {
153 int differences = 0;
154
155 float* buffer_view =
156 reinterpret_cast<float*>(string_as_array(&received_samples_));
157 const int channels = params_.channels();
158 const int frames =
159 received_samples_.size() / sizeof(float) / params_.channels();
160 for (int ch = 0; ch < channels; ++ch) {
161 for (int si = 0, di = ch; si < frames; ++si, di += channels)
162 differences += (buffer_view[di] != channel_data_[ch][si]);
163 }
164
165 ASSERT_EQ(0, differences);
166 }
167
168 protected:
169 // Generate random samples given a random seed.
170 float* GenerateSamples(int random_seed, size_t size) {
171 float* samples = static_cast<float*>(base::AlignedAlloc(
172 size * sizeof(float), media::AudioBus::kChannelAlignment));
173
174 srand(random_seed);
175 for (size_t i = 0; i < size; ++i)
176 samples[i] = (2.0 * rand() / RAND_MAX) - 1;
177
178 return samples;
179 }
180
181 bool IsRecording() {
182 recorder_->FlushAudioLoopForTesting();
183 return recorder_->is_recording_;
184 }
185
186 std::vector<float*> channel_data_;
187 media::AudioParameters params_;
188 size_t total_samples_;
189
190 AudioRecorder* recorder_;
191
192 std::string received_samples_;
193
194 scoped_ptr<base::RunLoop> run_loop_;
195 content::TestBrowserThreadBundle thread_bundle_;
196 };
197
198 TEST_F(AudioRecorderTest, BasicRecordAndStop) {
199 CreateSimpleRecorder();
200
201 recorder_->Record();
202 EXPECT_TRUE(IsRecording());
203 recorder_->Stop();
204 EXPECT_FALSE(IsRecording());
205 recorder_->Record();
206
207 EXPECT_TRUE(IsRecording());
208 recorder_->Stop();
209 EXPECT_FALSE(IsRecording());
210 recorder_->Record();
211
212 EXPECT_TRUE(IsRecording());
213 recorder_->Stop();
214 EXPECT_FALSE(IsRecording());
215
216 DeleteRecorder();
217 }
218
219 TEST_F(AudioRecorderTest, OutOfOrderRecordAndStopMultiple) {
220 CreateSimpleRecorder();
221
222 recorder_->Stop();
223 recorder_->Stop();
224 recorder_->Stop();
225 EXPECT_FALSE(IsRecording());
226
227 recorder_->Record();
228 recorder_->Record();
229 EXPECT_TRUE(IsRecording());
230
231 recorder_->Stop();
232 recorder_->Stop();
233 EXPECT_FALSE(IsRecording());
234
235 DeleteRecorder();
236 }
237
238 TEST_F(AudioRecorderTest, RecordingEndToEnd) {
239 const int kNumSamples = 48000 * 3;
240 CreateRecorder(
241 kDefaultChannels, kDefaultSampleRate, kDefaultBitsPerSample, kNumSamples);
242
243 RecordAndVerifySamples();
244
245 DeleteRecorder();
246 }
247
248 // TODO(rkc): Add tests with recording different sample rates.
249
250 } // namespace copresence
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698