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.
5 #include "components/copresence/mediums/audio/audio_recorder.h"
8 #include "base/memory/aligned_memory.h"
9 #include "base/run_loop.h"
10 #include "components/copresence/mediums/audio/audio_recorder_impl.h"
11 #include "components/copresence/public/copresence_constants.h"
12 #include "components/copresence/test/audio_test_support.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"
21 class TestAudioInputStream
: public media::AudioInputStream
{
23 TestAudioInputStream(const media::AudioParameters
& params
,
24 const std::vector
<float*> channel_data
,
26 : callback_(nullptr), 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
);
33 ~TestAudioInputStream() override
{}
35 bool Open() override
{ return true; }
36 void Start(AudioInputCallback
* callback
) override
{
39 media::AudioManager::Get()->GetTaskRunner()->PostTask(
41 base::Bind(&TestAudioInputStream::SimulateRecording
,
42 base::Unretained(this)));
44 void Stop() override
{}
45 void Close() override
{}
46 double GetMaxVolume() override
{ return 1.0; }
47 void SetVolume(double volume
) override
{}
48 double GetVolume() override
{ return 1.0; }
49 bool SetAutomaticGainControl(bool enabled
) override
{ return false; }
50 bool GetAutomaticGainControl() override
{ return true; }
51 bool IsMuted() override
{ return false; }
54 void SimulateRecording() {
55 const int fpb
= params_
.frames_per_buffer();
56 for (int i
= 0; i
< buffer_
->frames() / fpb
; ++i
) {
57 scoped_ptr
<media::AudioBus
> source
= media::AudioBus::Create(2, fpb
);
58 buffer_
->CopyPartialFramesTo(i
* fpb
, fpb
, 0, source
.get());
59 callback_
->OnData(this, source
.get(), fpb
, 1.0);
63 AudioInputCallback
* callback_
;
64 media::AudioParameters params_
;
65 scoped_ptr
<media::AudioBus
> buffer_
;
67 DISALLOW_COPY_AND_ASSIGN(TestAudioInputStream
);
72 namespace copresence
{
74 class AudioRecorderTest
: public testing::Test
{
76 AudioRecorderTest() : total_samples_(0), recorder_(nullptr) {
77 if (!media::AudioManager::Get())
78 media::AudioManager::CreateForTesting();
81 ~AudioRecorderTest() override
{
83 for (size_t i
= 0; i
< channel_data_
.size(); ++i
)
84 base::AlignedFree(channel_data_
[i
]);
87 void CreateSimpleRecorder() {
89 recorder_
= new AudioRecorderImpl();
90 recorder_
->Initialize(
91 base::Bind(&AudioRecorderTest::DecodeSamples
, base::Unretained(this)));
94 void CreateRecorder(size_t channels
,
96 size_t bits_per_sample
,
99 params_
.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY
,
100 kDefaultChannelLayout
,
106 channel_data_
.clear();
107 channel_data_
.push_back(GenerateSamples(0x1337, samples
));
108 channel_data_
.push_back(GenerateSamples(0x7331, samples
));
110 total_samples_
= samples
;
112 recorder_
= new AudioRecorderImpl();
113 recorder_
->set_input_stream_for_testing(
114 new TestAudioInputStream(params_
, channel_data_
, samples
));
115 recorder_
->set_params_for_testing(new media::AudioParameters(params_
));
116 recorder_
->Initialize(
117 base::Bind(&AudioRecorderTest::DecodeSamples
, base::Unretained(this)));
120 void DeleteRecorder() {
123 recorder_
->Finalize();
127 void RecordAndVerifySamples() {
128 received_samples_
.clear();
129 run_loop_
.reset(new base::RunLoop());
134 void DecodeSamples(const std::string
& samples
) {
135 received_samples_
+= samples
;
136 // We expect one less decode than our total samples would ideally have
137 // triggered since we process data in 4k chunks. So our sample processing
138 // will never rarely be perfectly aligned with 0.5s worth of samples, hence
139 // we will almost always run with a buffer of leftover samples that will
140 // not get sent to this callback since the recorder will be waiting for
142 const size_t decode_buffer
= params_
.sample_rate() / 2; // 0.5s
143 const size_t expected_samples
=
144 (total_samples_
/ decode_buffer
- 1) * decode_buffer
;
145 const size_t expected_samples_size
=
146 expected_samples
* sizeof(float) * params_
.channels();
147 if (received_samples_
.size() == expected_samples_size
) {
153 void VerifySamples() {
157 reinterpret_cast<float*>(string_as_array(&received_samples_
));
158 const int channels
= params_
.channels();
160 received_samples_
.size() / sizeof(float) / params_
.channels();
161 for (int ch
= 0; ch
< channels
; ++ch
) {
162 for (int si
= 0, di
= ch
; si
< frames
; ++si
, di
+= channels
)
163 differences
+= (buffer_view
[di
] != channel_data_
[ch
][si
]);
166 ASSERT_EQ(0, differences
);
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 PopulateSamples(0x1337, size
, samples
);
177 recorder_
->FlushAudioLoopForTesting();
178 return recorder_
->is_recording_
;
181 std::vector
<float*> channel_data_
;
182 media::AudioParameters params_
;
183 size_t total_samples_
;
185 // Deleted by calling Finalize() on the object.
186 AudioRecorderImpl
* recorder_
;
188 std::string received_samples_
;
190 scoped_ptr
<base::RunLoop
> run_loop_
;
191 content::TestBrowserThreadBundle thread_bundle_
;
194 // TODO(rkc): These tests are broken on all platforms.
195 // On Windows and Mac, we cannot use non-OS params. The tests need to be
196 // rewritten to use the params provided to us by the audio manager
197 // rather than setting our own params.
198 // On Linux, there is a memory leak in the audio code during initialization.
199 #define MAYBE_BasicRecordAndStop DISABLED_BasicRecordAndStop
200 #define MAYBE_OutOfOrderRecordAndStopMultiple DISABLED_OutOfOrderRecordAndStopMultiple
201 #define MAYBE_RecordingEndToEnd DISABLED_RecordingEndToEnd
203 TEST_F(AudioRecorderTest
, MAYBE_BasicRecordAndStop
) {
204 CreateSimpleRecorder();
207 EXPECT_TRUE(IsRecording());
209 EXPECT_FALSE(IsRecording());
212 EXPECT_TRUE(IsRecording());
214 EXPECT_FALSE(IsRecording());
217 EXPECT_TRUE(IsRecording());
219 EXPECT_FALSE(IsRecording());
224 TEST_F(AudioRecorderTest
, MAYBE_OutOfOrderRecordAndStopMultiple
) {
225 CreateSimpleRecorder();
230 EXPECT_FALSE(IsRecording());
234 EXPECT_TRUE(IsRecording());
238 EXPECT_FALSE(IsRecording());
243 TEST_F(AudioRecorderTest
, MAYBE_RecordingEndToEnd
) {
244 const int kNumSamples
= 48000 * 3;
246 kDefaultChannels
, kDefaultSampleRate
, kDefaultBitsPerSample
, kNumSamples
);
248 RecordAndVerifySamples();
253 // TODO(rkc): Add tests with recording different sample rates.
255 } // namespace copresence