Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / media / audio / mac / audio_low_latency_input_mac_unittest.cc
blobb1a8b3b69aca00c8da65caa9003b2af3d59bc052
1 // Copyright (c) 2012 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 "base/basictypes.h"
6 #include "base/environment.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/run_loop.h"
9 #include "base/test/test_timeouts.h"
10 #include "base/threading/platform_thread.h"
11 #include "media/audio/audio_io.h"
12 #include "media/audio/audio_manager_base.h"
13 #include "media/audio/audio_unittest_util.h"
14 #include "media/audio/mac/audio_low_latency_input_mac.h"
15 #include "media/base/seekable_buffer.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gtest/include/gtest/gtest.h"
19 using ::testing::_;
20 using ::testing::AnyNumber;
21 using ::testing::AtLeast;
22 using ::testing::Ge;
23 using ::testing::NotNull;
25 namespace media {
27 ACTION_P4(CheckCountAndPostQuitTask, count, limit, loop, closure) {
28 if (++*count >= limit) {
29 loop->PostTask(FROM_HERE, closure);
33 class MockAudioInputCallback : public AudioInputStream::AudioInputCallback {
34 public:
35 MOCK_METHOD4(OnData,
36 void(AudioInputStream* stream,
37 const AudioBus* src,
38 uint32 hardware_delay_bytes,
39 double volume));
40 MOCK_METHOD1(OnError, void(AudioInputStream* stream));
43 // This audio sink implementation should be used for manual tests only since
44 // the recorded data is stored on a raw binary data file.
45 // The last test (WriteToFileAudioSink) - which is disabled by default -
46 // can use this audio sink to store the captured data on a file for offline
47 // analysis.
48 class WriteToFileAudioSink : public AudioInputStream::AudioInputCallback {
49 public:
50 // Allocate space for ~10 seconds of data @ 48kHz in stereo:
51 // 2 bytes per sample, 2 channels, 10ms @ 48kHz, 10 seconds <=> 1920000 bytes.
52 static const int kMaxBufferSize = 2 * 2 * 480 * 100 * 10;
54 explicit WriteToFileAudioSink(const char* file_name)
55 : buffer_(0, kMaxBufferSize),
56 file_(fopen(file_name, "wb")),
57 bytes_to_write_(0) {
60 ~WriteToFileAudioSink() override {
61 int bytes_written = 0;
62 while (bytes_written < bytes_to_write_) {
63 const uint8* chunk;
64 int chunk_size;
66 // Stop writing if no more data is available.
67 if (!buffer_.GetCurrentChunk(&chunk, &chunk_size))
68 break;
70 // Write recorded data chunk to the file and prepare for next chunk.
71 fwrite(chunk, 1, chunk_size, file_);
72 buffer_.Seek(chunk_size);
73 bytes_written += chunk_size;
75 fclose(file_);
78 // AudioInputStream::AudioInputCallback implementation.
79 void OnData(AudioInputStream* stream,
80 const AudioBus* src,
81 uint32 hardware_delay_bytes,
82 double volume) override {
83 const int num_samples = src->frames() * src->channels();
84 scoped_ptr<int16> interleaved(new int16[num_samples]);
85 const int bytes_per_sample = sizeof(*interleaved);
86 src->ToInterleaved(src->frames(), bytes_per_sample, interleaved.get());
88 // Store data data in a temporary buffer to avoid making blocking
89 // fwrite() calls in the audio callback. The complete buffer will be
90 // written to file in the destructor.
91 const int size = bytes_per_sample * num_samples;
92 if (buffer_.Append((const uint8*)interleaved.get(), size)) {
93 bytes_to_write_ += size;
97 void OnError(AudioInputStream* stream) override {}
99 private:
100 media::SeekableBuffer buffer_;
101 FILE* file_;
102 int bytes_to_write_;
105 class MacAudioInputTest : public testing::Test {
106 protected:
107 MacAudioInputTest()
108 : message_loop_(base::MessageLoop::TYPE_UI),
109 audio_manager_(AudioManager::CreateForTesting()) {
110 // Wait for the AudioManager to finish any initialization on the audio loop.
111 base::RunLoop().RunUntilIdle();
114 ~MacAudioInputTest() override { base::RunLoop().RunUntilIdle(); }
116 bool InputDevicesAvailable() {
117 return audio_manager_->HasAudioInputDevices();
120 // Convenience method which creates a default AudioInputStream object using
121 // a 10ms frame size and a sample rate which is set to the hardware sample
122 // rate.
123 AudioInputStream* CreateDefaultAudioInputStream() {
124 int fs = static_cast<int>(AUAudioInputStream::HardwareSampleRate());
125 int samples_per_packet = fs / 100;
126 AudioInputStream* ais = audio_manager_->MakeAudioInputStream(
127 AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
128 CHANNEL_LAYOUT_STEREO, fs, 16, samples_per_packet),
129 AudioManagerBase::kDefaultDeviceId);
130 EXPECT_TRUE(ais);
131 return ais;
134 // Convenience method which creates an AudioInputStream object with a
135 // specified channel layout.
136 AudioInputStream* CreateAudioInputStream(ChannelLayout channel_layout) {
137 int fs = static_cast<int>(AUAudioInputStream::HardwareSampleRate());
138 int samples_per_packet = fs / 100;
139 AudioInputStream* ais = audio_manager_->MakeAudioInputStream(
140 AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
141 channel_layout, fs, 16, samples_per_packet),
142 AudioManagerBase::kDefaultDeviceId);
143 EXPECT_TRUE(ais);
144 return ais;
147 base::MessageLoop message_loop_;
148 scoped_ptr<AudioManager> audio_manager_;
151 // Test Create(), Close().
152 TEST_F(MacAudioInputTest, AUAudioInputStreamCreateAndClose) {
153 ABORT_AUDIO_TEST_IF_NOT(InputDevicesAvailable());
154 AudioInputStream* ais = CreateDefaultAudioInputStream();
155 ais->Close();
158 // Test Open(), Close().
159 TEST_F(MacAudioInputTest, AUAudioInputStreamOpenAndClose) {
160 ABORT_AUDIO_TEST_IF_NOT(InputDevicesAvailable());
161 AudioInputStream* ais = CreateDefaultAudioInputStream();
162 EXPECT_TRUE(ais->Open());
163 ais->Close();
166 // Test Open(), Start(), Close().
167 TEST_F(MacAudioInputTest, AUAudioInputStreamOpenStartAndClose) {
168 ABORT_AUDIO_TEST_IF_NOT(InputDevicesAvailable());
169 AudioInputStream* ais = CreateDefaultAudioInputStream();
170 EXPECT_TRUE(ais->Open());
171 MockAudioInputCallback sink;
172 ais->Start(&sink);
173 ais->Close();
176 // Test Open(), Start(), Stop(), Close().
177 TEST_F(MacAudioInputTest, AUAudioInputStreamOpenStartStopAndClose) {
178 ABORT_AUDIO_TEST_IF_NOT(InputDevicesAvailable());
179 AudioInputStream* ais = CreateDefaultAudioInputStream();
180 EXPECT_TRUE(ais->Open());
181 MockAudioInputCallback sink;
182 ais->Start(&sink);
183 ais->Stop();
184 ais->Close();
187 // Test some additional calling sequences.
188 TEST_F(MacAudioInputTest, AUAudioInputStreamMiscCallingSequences) {
189 ABORT_AUDIO_TEST_IF_NOT(InputDevicesAvailable());
190 AudioInputStream* ais = CreateDefaultAudioInputStream();
191 AUAudioInputStream* auais = static_cast<AUAudioInputStream*>(ais);
193 // Open(), Open() should fail the second time.
194 EXPECT_TRUE(ais->Open());
195 EXPECT_FALSE(ais->Open());
197 MockAudioInputCallback sink;
199 // Start(), Start() is a valid calling sequence (second call does nothing).
200 ais->Start(&sink);
201 EXPECT_TRUE(auais->started());
202 ais->Start(&sink);
203 EXPECT_TRUE(auais->started());
205 // Stop(), Stop() is a valid calling sequence (second call does nothing).
206 ais->Stop();
207 EXPECT_FALSE(auais->started());
208 ais->Stop();
209 EXPECT_FALSE(auais->started());
211 ais->Close();
214 // Verify that recording starts and stops correctly in mono using mocked sink.
215 TEST_F(MacAudioInputTest, AUAudioInputStreamVerifyMonoRecording) {
216 ABORT_AUDIO_TEST_IF_NOT(InputDevicesAvailable());
218 int count = 0;
220 // Create an audio input stream which records in mono.
221 AudioInputStream* ais = CreateAudioInputStream(CHANNEL_LAYOUT_MONO);
222 EXPECT_TRUE(ais->Open());
224 MockAudioInputCallback sink;
226 // We use 10ms packets and will run the test until ten packets are received.
227 // All should contain valid packets of the same size and a valid delay
228 // estimate.
229 base::RunLoop run_loop;
230 EXPECT_CALL(sink, OnData(ais, NotNull(), _, _))
231 .Times(AtLeast(10))
232 .WillRepeatedly(CheckCountAndPostQuitTask(
233 &count, 10, &message_loop_, run_loop.QuitClosure()));
234 ais->Start(&sink);
235 run_loop.Run();
236 ais->Stop();
237 ais->Close();
240 // Verify that recording starts and stops correctly in mono using mocked sink.
241 TEST_F(MacAudioInputTest, AUAudioInputStreamVerifyStereoRecording) {
242 ABORT_AUDIO_TEST_IF_NOT(InputDevicesAvailable());
244 int count = 0;
246 // Create an audio input stream which records in stereo.
247 AudioInputStream* ais = CreateAudioInputStream(CHANNEL_LAYOUT_STEREO);
248 EXPECT_TRUE(ais->Open());
250 MockAudioInputCallback sink;
252 // We use 10ms packets and will run the test until ten packets are received.
253 // All should contain valid packets of the same size and a valid delay
254 // estimate.
255 // TODO(henrika): http://crbug.com/154352 forced us to run the capture side
256 // using a native buffer size of 128 audio frames and combine it with a FIFO
257 // to match the requested size by the client. This change might also have
258 // modified the delay estimates since the existing Ge(bytes_per_packet) for
259 // parameter #4 does no longer pass. I am removing this restriction here to
260 // ensure that we can land the patch but will revisit this test again when
261 // more analysis of the delay estimates are done.
262 base::RunLoop run_loop;
263 EXPECT_CALL(sink, OnData(ais, NotNull(), _, _))
264 .Times(AtLeast(10))
265 .WillRepeatedly(CheckCountAndPostQuitTask(
266 &count, 10, &message_loop_, run_loop.QuitClosure()));
267 ais->Start(&sink);
268 run_loop.Run();
269 ais->Stop();
270 ais->Close();
273 // This test is intended for manual tests and should only be enabled
274 // when it is required to store the captured data on a local file.
275 // By default, GTest will print out YOU HAVE 1 DISABLED TEST.
276 // To include disabled tests in test execution, just invoke the test program
277 // with --gtest_also_run_disabled_tests or set the GTEST_ALSO_RUN_DISABLED_TESTS
278 // environment variable to a value greater than 0.
279 TEST_F(MacAudioInputTest, DISABLED_AUAudioInputStreamRecordToFile) {
280 ABORT_AUDIO_TEST_IF_NOT(InputDevicesAvailable());
281 const char* file_name = "out_stereo_10sec.pcm";
283 int fs = static_cast<int>(AUAudioInputStream::HardwareSampleRate());
284 AudioInputStream* ais = CreateDefaultAudioInputStream();
285 EXPECT_TRUE(ais->Open());
287 fprintf(stderr, " File name : %s\n", file_name);
288 fprintf(stderr, " Sample rate: %d\n", fs);
289 WriteToFileAudioSink file_sink(file_name);
290 fprintf(stderr, " >> Speak into the mic while recording...\n");
291 ais->Start(&file_sink);
292 base::PlatformThread::Sleep(TestTimeouts::action_timeout());
293 ais->Stop();
294 fprintf(stderr, " >> Recording has stopped.\n");
295 ais->Close();
298 } // namespace media