Mailbox support for texture layers.
[chromium-blink-merge.git] / media / audio / mac / audio_low_latency_input_mac_unittest.cc
blobe8ef33d10a8a1c68be41153ed9ff2fa21d1106ce
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.h"
8 #include "base/test/test_timeouts.h"
9 #include "base/threading/platform_thread.h"
10 #include "media/audio/audio_io.h"
11 #include "media/audio/audio_manager_base.h"
12 #include "media/audio/mac/audio_low_latency_input_mac.h"
13 #include "media/base/seekable_buffer.h"
14 #include "testing/gmock/include/gmock/gmock.h"
15 #include "testing/gtest/include/gtest/gtest.h"
17 using ::testing::_;
18 using ::testing::AnyNumber;
19 using ::testing::AtLeast;
20 using ::testing::Ge;
21 using ::testing::NotNull;
23 namespace media {
25 ACTION_P3(CheckCountAndPostQuitTask, count, limit, loop) {
26 if (++*count >= limit) {
27 loop->PostTask(FROM_HERE, MessageLoop::QuitClosure());
31 class MockAudioInputCallback : public AudioInputStream::AudioInputCallback {
32 public:
33 MOCK_METHOD5(OnData, void(AudioInputStream* stream,
34 const uint8* src, uint32 size,
35 uint32 hardware_delay_bytes, double volume));
36 MOCK_METHOD1(OnClose, void(AudioInputStream* stream));
37 MOCK_METHOD2(OnError, void(AudioInputStream* stream, int code));
40 // This audio sink implementation should be used for manual tests only since
41 // the recorded data is stored on a raw binary data file.
42 // The last test (WriteToFileAudioSink) - which is disabled by default -
43 // can use this audio sink to store the captured data on a file for offline
44 // analysis.
45 class WriteToFileAudioSink : public AudioInputStream::AudioInputCallback {
46 public:
47 // Allocate space for ~10 seconds of data @ 48kHz in stereo:
48 // 2 bytes per sample, 2 channels, 10ms @ 48kHz, 10 seconds <=> 1920000 bytes.
49 static const int kMaxBufferSize = 2 * 2 * 480 * 100 * 10;
51 explicit WriteToFileAudioSink(const char* file_name)
52 : buffer_(0, kMaxBufferSize),
53 file_(fopen(file_name, "wb")),
54 bytes_to_write_(0) {
57 virtual ~WriteToFileAudioSink() {
58 int bytes_written = 0;
59 while (bytes_written < bytes_to_write_) {
60 const uint8* chunk;
61 int chunk_size;
63 // Stop writing if no more data is available.
64 if (!buffer_.GetCurrentChunk(&chunk, &chunk_size))
65 break;
67 // Write recorded data chunk to the file and prepare for next chunk.
68 fwrite(chunk, 1, chunk_size, file_);
69 buffer_.Seek(chunk_size);
70 bytes_written += chunk_size;
72 fclose(file_);
75 // AudioInputStream::AudioInputCallback implementation.
76 virtual void OnData(AudioInputStream* stream,
77 const uint8* src, uint32 size,
78 uint32 hardware_delay_bytes, double volume) {
79 // Store data data in a temporary buffer to avoid making blocking
80 // fwrite() calls in the audio callback. The complete buffer will be
81 // written to file in the destructor.
82 if (buffer_.Append(src, size)) {
83 bytes_to_write_ += size;
87 virtual void OnClose(AudioInputStream* stream) {}
88 virtual void OnError(AudioInputStream* stream, int code) {}
90 private:
91 media::SeekableBuffer buffer_;
92 FILE* file_;
93 int bytes_to_write_;
96 class MacAudioInputTest : public testing::Test {
97 protected:
98 MacAudioInputTest() : audio_manager_(AudioManager::Create()) {}
99 virtual ~MacAudioInputTest() {}
101 // Convenience method which ensures that we are not running on the build
102 // bots and that at least one valid input device can be found.
103 bool CanRunAudioTests() {
104 bool has_input = audio_manager_->HasAudioInputDevices();
105 if (!has_input)
106 LOG(WARNING) << "No input devices detected";
107 return has_input;
110 // Convenience method which creates a default AudioInputStream object using
111 // a 10ms frame size and a sample rate which is set to the hardware sample
112 // rate.
113 AudioInputStream* CreateDefaultAudioInputStream() {
114 int fs = static_cast<int>(AUAudioInputStream::HardwareSampleRate());
115 int samples_per_packet = fs / 100;
116 AudioInputStream* ais = audio_manager_->MakeAudioInputStream(
117 AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
118 CHANNEL_LAYOUT_STEREO, fs, 16, samples_per_packet),
119 AudioManagerBase::kDefaultDeviceId);
120 EXPECT_TRUE(ais);
121 return ais;
124 // Convenience method which creates an AudioInputStream object with a
125 // specified channel layout.
126 AudioInputStream* CreateAudioInputStream(ChannelLayout channel_layout) {
127 int fs = static_cast<int>(AUAudioInputStream::HardwareSampleRate());
128 int samples_per_packet = fs / 100;
129 AudioInputStream* ais = audio_manager_->MakeAudioInputStream(
130 AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
131 channel_layout, fs, 16, samples_per_packet),
132 AudioManagerBase::kDefaultDeviceId);
133 EXPECT_TRUE(ais);
134 return ais;
137 scoped_ptr<AudioManager> audio_manager_;
140 // Test Create(), Close().
141 TEST_F(MacAudioInputTest, AUAudioInputStreamCreateAndClose) {
142 if (!CanRunAudioTests())
143 return;
144 AudioInputStream* ais = CreateDefaultAudioInputStream();
145 ais->Close();
148 // Test Open(), Close().
149 TEST_F(MacAudioInputTest, AUAudioInputStreamOpenAndClose) {
150 if (!CanRunAudioTests())
151 return;
152 AudioInputStream* ais = CreateDefaultAudioInputStream();
153 EXPECT_TRUE(ais->Open());
154 ais->Close();
157 // Test Open(), Start(), Close().
158 TEST_F(MacAudioInputTest, AUAudioInputStreamOpenStartAndClose) {
159 if (!CanRunAudioTests())
160 return;
161 AudioInputStream* ais = CreateDefaultAudioInputStream();
162 EXPECT_TRUE(ais->Open());
163 MockAudioInputCallback sink;
164 ais->Start(&sink);
165 EXPECT_CALL(sink, OnClose(ais))
166 .Times(1);
167 ais->Close();
170 // Test Open(), Start(), Stop(), Close().
171 TEST_F(MacAudioInputTest, AUAudioInputStreamOpenStartStopAndClose) {
172 if (!CanRunAudioTests())
173 return;
174 AudioInputStream* ais = CreateDefaultAudioInputStream();
175 EXPECT_TRUE(ais->Open());
176 MockAudioInputCallback sink;
177 ais->Start(&sink);
178 ais->Stop();
179 EXPECT_CALL(sink, OnClose(ais))
180 .Times(1);
181 ais->Close();
184 // Test some additional calling sequences.
185 TEST_F(MacAudioInputTest, AUAudioInputStreamMiscCallingSequences) {
186 if (!CanRunAudioTests())
187 return;
188 AudioInputStream* ais = CreateDefaultAudioInputStream();
189 AUAudioInputStream* auais = static_cast<AUAudioInputStream*>(ais);
191 // Open(), Open() should fail the second time.
192 EXPECT_TRUE(ais->Open());
193 EXPECT_FALSE(ais->Open());
195 MockAudioInputCallback sink;
197 // Start(), Start() is a valid calling sequence (second call does nothing).
198 ais->Start(&sink);
199 EXPECT_TRUE(auais->started());
200 ais->Start(&sink);
201 EXPECT_TRUE(auais->started());
203 // Stop(), Stop() is a valid calling sequence (second call does nothing).
204 ais->Stop();
205 EXPECT_FALSE(auais->started());
206 ais->Stop();
207 EXPECT_FALSE(auais->started());
209 EXPECT_CALL(sink, OnClose(ais))
210 .Times(1);
211 ais->Close();
214 // Verify that recording starts and stops correctly in mono using mocked sink.
215 TEST_F(MacAudioInputTest, AUAudioInputStreamVerifyMonoRecording) {
216 if (!CanRunAudioTests())
217 return;
219 int count = 0;
220 MessageLoopForUI loop;
222 // Create an audio input stream which records in mono.
223 AudioInputStream* ais = CreateAudioInputStream(CHANNEL_LAYOUT_MONO);
224 EXPECT_TRUE(ais->Open());
226 int fs = static_cast<int>(AUAudioInputStream::HardwareSampleRate());
227 int samples_per_packet = fs / 100;
228 int bits_per_sample = 16;
229 uint32 bytes_per_packet = samples_per_packet * (bits_per_sample / 8);
231 MockAudioInputCallback sink;
233 // We use 10ms packets and will run the test until ten packets are received.
234 // All should contain valid packets of the same size and a valid delay
235 // estimate.
236 EXPECT_CALL(sink, OnData(ais, NotNull(), bytes_per_packet, _, _))
237 .Times(AtLeast(10))
238 .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop));
239 ais->Start(&sink);
240 loop.Run();
241 ais->Stop();
243 // Verify that the sink receieves OnClose() call when calling Close().
244 EXPECT_CALL(sink, OnClose(ais))
245 .Times(1);
246 ais->Close();
249 // Verify that recording starts and stops correctly in mono using mocked sink.
250 TEST_F(MacAudioInputTest, AUAudioInputStreamVerifyStereoRecording) {
251 if (!CanRunAudioTests())
252 return;
254 int count = 0;
255 MessageLoopForUI loop;
257 // Create an audio input stream which records in stereo.
258 AudioInputStream* ais = CreateAudioInputStream(CHANNEL_LAYOUT_STEREO);
259 EXPECT_TRUE(ais->Open());
261 int fs = static_cast<int>(AUAudioInputStream::HardwareSampleRate());
262 int samples_per_packet = fs / 100;
263 int bits_per_sample = 16;
264 uint32 bytes_per_packet = 2 * samples_per_packet * (bits_per_sample / 8);
266 MockAudioInputCallback sink;
268 // We use 10ms packets and will run the test until ten packets are received.
269 // All should contain valid packets of the same size and a valid delay
270 // estimate.
271 // TODO(henrika): http://crbug.com/154352 forced us to run the capture side
272 // using a native buffer size of 128 audio frames and combine it with a FIFO
273 // to match the requested size by the client. This change might also have
274 // modified the delay estimates since the existing Ge(bytes_per_packet) for
275 // parameter #4 does no longer pass. I am removing this restriction here to
276 // ensure that we can land the patch but will revisit this test again when
277 // more analysis of the delay estimates are done.
278 EXPECT_CALL(sink, OnData(ais, NotNull(), bytes_per_packet, _, _))
279 .Times(AtLeast(10))
280 .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop));
281 ais->Start(&sink);
282 loop.Run();
283 ais->Stop();
285 // Verify that the sink receieves OnClose() call when calling Close().
286 EXPECT_CALL(sink, OnClose(ais))
287 .Times(1);
288 ais->Close();
291 // This test is intended for manual tests and should only be enabled
292 // when it is required to store the captured data on a local file.
293 // By default, GTest will print out YOU HAVE 1 DISABLED TEST.
294 // To include disabled tests in test execution, just invoke the test program
295 // with --gtest_also_run_disabled_tests or set the GTEST_ALSO_RUN_DISABLED_TESTS
296 // environment variable to a value greater than 0.
297 TEST_F(MacAudioInputTest, DISABLED_AUAudioInputStreamRecordToFile) {
298 if (!CanRunAudioTests())
299 return;
300 const char* file_name = "out_stereo_10sec.pcm";
302 int fs = static_cast<int>(AUAudioInputStream::HardwareSampleRate());
303 AudioInputStream* ais = CreateDefaultAudioInputStream();
304 EXPECT_TRUE(ais->Open());
306 fprintf(stderr, " File name : %s\n", file_name);
307 fprintf(stderr, " Sample rate: %d\n", fs);
308 WriteToFileAudioSink file_sink(file_name);
309 fprintf(stderr, " >> Speak into the mic while recording...\n");
310 ais->Start(&file_sink);
311 base::PlatformThread::Sleep(TestTimeouts::action_timeout());
312 ais->Stop();
313 fprintf(stderr, " >> Recording has stopped.\n");
314 ais->Close();
317 } // namespace media