Delete chrome.mediaGalleriesPrivate because the functionality unique to it has since...
[chromium-blink-merge.git] / media / audio / mac / audio_low_latency_input_mac_unittest.cc
blob03ec610c8815c86a363afb068737e36a45cd1866
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/mac/audio_low_latency_input_mac.h"
14 #include "media/base/seekable_buffer.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
18 using ::testing::_;
19 using ::testing::AnyNumber;
20 using ::testing::AtLeast;
21 using ::testing::Ge;
22 using ::testing::NotNull;
24 namespace media {
26 ACTION_P4(CheckCountAndPostQuitTask, count, limit, loop, closure) {
27 if (++*count >= limit) {
28 loop->PostTask(FROM_HERE, closure);
32 class MockAudioInputCallback : public AudioInputStream::AudioInputCallback {
33 public:
34 MOCK_METHOD4(OnData,
35 void(AudioInputStream* stream,
36 const AudioBus* src,
37 uint32 hardware_delay_bytes,
38 double volume));
39 MOCK_METHOD1(OnError, void(AudioInputStream* stream));
42 // This audio sink implementation should be used for manual tests only since
43 // the recorded data is stored on a raw binary data file.
44 // The last test (WriteToFileAudioSink) - which is disabled by default -
45 // can use this audio sink to store the captured data on a file for offline
46 // analysis.
47 class WriteToFileAudioSink : public AudioInputStream::AudioInputCallback {
48 public:
49 // Allocate space for ~10 seconds of data @ 48kHz in stereo:
50 // 2 bytes per sample, 2 channels, 10ms @ 48kHz, 10 seconds <=> 1920000 bytes.
51 static const int kMaxBufferSize = 2 * 2 * 480 * 100 * 10;
53 explicit WriteToFileAudioSink(const char* file_name)
54 : buffer_(0, kMaxBufferSize),
55 file_(fopen(file_name, "wb")),
56 bytes_to_write_(0) {
59 ~WriteToFileAudioSink() override {
60 int bytes_written = 0;
61 while (bytes_written < bytes_to_write_) {
62 const uint8* chunk;
63 int chunk_size;
65 // Stop writing if no more data is available.
66 if (!buffer_.GetCurrentChunk(&chunk, &chunk_size))
67 break;
69 // Write recorded data chunk to the file and prepare for next chunk.
70 fwrite(chunk, 1, chunk_size, file_);
71 buffer_.Seek(chunk_size);
72 bytes_written += chunk_size;
74 fclose(file_);
77 // AudioInputStream::AudioInputCallback implementation.
78 void OnData(AudioInputStream* stream,
79 const AudioBus* src,
80 uint32 hardware_delay_bytes,
81 double volume) override {
82 const int num_samples = src->frames() * src->channels();
83 scoped_ptr<int16> interleaved(new int16[num_samples]);
84 const int bytes_per_sample = sizeof(*interleaved);
85 src->ToInterleaved(src->frames(), bytes_per_sample, interleaved.get());
87 // Store data data in a temporary buffer to avoid making blocking
88 // fwrite() calls in the audio callback. The complete buffer will be
89 // written to file in the destructor.
90 const int size = bytes_per_sample * num_samples;
91 if (buffer_.Append((const uint8*)interleaved.get(), size)) {
92 bytes_to_write_ += size;
96 void OnError(AudioInputStream* stream) override {}
98 private:
99 media::SeekableBuffer buffer_;
100 FILE* file_;
101 int bytes_to_write_;
104 class MacAudioInputTest : public testing::Test {
105 protected:
106 MacAudioInputTest()
107 : message_loop_(base::MessageLoop::TYPE_UI),
108 audio_manager_(AudioManager::CreateForTesting()) {
109 // Wait for the AudioManager to finish any initialization on the audio loop.
110 base::RunLoop().RunUntilIdle();
113 ~MacAudioInputTest() override { base::RunLoop().RunUntilIdle(); }
115 // Convenience method which ensures that we are not running on the build
116 // bots and that at least one valid input device can be found.
117 bool CanRunAudioTests() {
118 bool has_input = audio_manager_->HasAudioInputDevices();
119 if (!has_input)
120 LOG(WARNING) << "No input devices detected";
121 return has_input;
124 // Convenience method which creates a default AudioInputStream object using
125 // a 10ms frame size and a sample rate which is set to the hardware sample
126 // rate.
127 AudioInputStream* CreateDefaultAudioInputStream() {
128 int fs = static_cast<int>(AUAudioInputStream::HardwareSampleRate());
129 int samples_per_packet = fs / 100;
130 AudioInputStream* ais = audio_manager_->MakeAudioInputStream(
131 AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
132 CHANNEL_LAYOUT_STEREO, fs, 16, samples_per_packet),
133 AudioManagerBase::kDefaultDeviceId);
134 EXPECT_TRUE(ais);
135 return ais;
138 // Convenience method which creates an AudioInputStream object with a
139 // specified channel layout.
140 AudioInputStream* CreateAudioInputStream(ChannelLayout channel_layout) {
141 int fs = static_cast<int>(AUAudioInputStream::HardwareSampleRate());
142 int samples_per_packet = fs / 100;
143 AudioInputStream* ais = audio_manager_->MakeAudioInputStream(
144 AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
145 channel_layout, fs, 16, samples_per_packet),
146 AudioManagerBase::kDefaultDeviceId);
147 EXPECT_TRUE(ais);
148 return ais;
151 base::MessageLoop message_loop_;
152 scoped_ptr<AudioManager> audio_manager_;
155 // Test Create(), Close().
156 TEST_F(MacAudioInputTest, AUAudioInputStreamCreateAndClose) {
157 if (!CanRunAudioTests())
158 return;
159 AudioInputStream* ais = CreateDefaultAudioInputStream();
160 ais->Close();
163 // Test Open(), Close().
164 TEST_F(MacAudioInputTest, AUAudioInputStreamOpenAndClose) {
165 if (!CanRunAudioTests())
166 return;
167 AudioInputStream* ais = CreateDefaultAudioInputStream();
168 EXPECT_TRUE(ais->Open());
169 ais->Close();
172 // Test Open(), Start(), Close().
173 TEST_F(MacAudioInputTest, AUAudioInputStreamOpenStartAndClose) {
174 if (!CanRunAudioTests())
175 return;
176 AudioInputStream* ais = CreateDefaultAudioInputStream();
177 EXPECT_TRUE(ais->Open());
178 MockAudioInputCallback sink;
179 ais->Start(&sink);
180 ais->Close();
183 // Test Open(), Start(), Stop(), Close().
184 TEST_F(MacAudioInputTest, AUAudioInputStreamOpenStartStopAndClose) {
185 if (!CanRunAudioTests())
186 return;
187 AudioInputStream* ais = CreateDefaultAudioInputStream();
188 EXPECT_TRUE(ais->Open());
189 MockAudioInputCallback sink;
190 ais->Start(&sink);
191 ais->Stop();
192 ais->Close();
195 // Test some additional calling sequences.
196 TEST_F(MacAudioInputTest, AUAudioInputStreamMiscCallingSequences) {
197 if (!CanRunAudioTests())
198 return;
199 AudioInputStream* ais = CreateDefaultAudioInputStream();
200 AUAudioInputStream* auais = static_cast<AUAudioInputStream*>(ais);
202 // Open(), Open() should fail the second time.
203 EXPECT_TRUE(ais->Open());
204 EXPECT_FALSE(ais->Open());
206 MockAudioInputCallback sink;
208 // Start(), Start() is a valid calling sequence (second call does nothing).
209 ais->Start(&sink);
210 EXPECT_TRUE(auais->started());
211 ais->Start(&sink);
212 EXPECT_TRUE(auais->started());
214 // Stop(), Stop() is a valid calling sequence (second call does nothing).
215 ais->Stop();
216 EXPECT_FALSE(auais->started());
217 ais->Stop();
218 EXPECT_FALSE(auais->started());
220 ais->Close();
223 // Verify that recording starts and stops correctly in mono using mocked sink.
224 TEST_F(MacAudioInputTest, AUAudioInputStreamVerifyMonoRecording) {
225 if (!CanRunAudioTests())
226 return;
228 int count = 0;
230 // Create an audio input stream which records in mono.
231 AudioInputStream* ais = CreateAudioInputStream(CHANNEL_LAYOUT_MONO);
232 EXPECT_TRUE(ais->Open());
234 MockAudioInputCallback sink;
236 // We use 10ms packets and will run the test until ten packets are received.
237 // All should contain valid packets of the same size and a valid delay
238 // estimate.
239 base::RunLoop run_loop;
240 EXPECT_CALL(sink, OnData(ais, NotNull(), _, _))
241 .Times(AtLeast(10))
242 .WillRepeatedly(CheckCountAndPostQuitTask(
243 &count, 10, &message_loop_, run_loop.QuitClosure()));
244 ais->Start(&sink);
245 run_loop.Run();
246 ais->Stop();
247 ais->Close();
250 // Verify that recording starts and stops correctly in mono using mocked sink.
251 TEST_F(MacAudioInputTest, AUAudioInputStreamVerifyStereoRecording) {
252 if (!CanRunAudioTests())
253 return;
255 int count = 0;
257 // Create an audio input stream which records in stereo.
258 AudioInputStream* ais = CreateAudioInputStream(CHANNEL_LAYOUT_STEREO);
259 EXPECT_TRUE(ais->Open());
261 MockAudioInputCallback sink;
263 // We use 10ms packets and will run the test until ten packets are received.
264 // All should contain valid packets of the same size and a valid delay
265 // estimate.
266 // TODO(henrika): http://crbug.com/154352 forced us to run the capture side
267 // using a native buffer size of 128 audio frames and combine it with a FIFO
268 // to match the requested size by the client. This change might also have
269 // modified the delay estimates since the existing Ge(bytes_per_packet) for
270 // parameter #4 does no longer pass. I am removing this restriction here to
271 // ensure that we can land the patch but will revisit this test again when
272 // more analysis of the delay estimates are done.
273 base::RunLoop run_loop;
274 EXPECT_CALL(sink, OnData(ais, NotNull(), _, _))
275 .Times(AtLeast(10))
276 .WillRepeatedly(CheckCountAndPostQuitTask(
277 &count, 10, &message_loop_, run_loop.QuitClosure()));
278 ais->Start(&sink);
279 run_loop.Run();
280 ais->Stop();
281 ais->Close();
284 // This test is intended for manual tests and should only be enabled
285 // when it is required to store the captured data on a local file.
286 // By default, GTest will print out YOU HAVE 1 DISABLED TEST.
287 // To include disabled tests in test execution, just invoke the test program
288 // with --gtest_also_run_disabled_tests or set the GTEST_ALSO_RUN_DISABLED_TESTS
289 // environment variable to a value greater than 0.
290 TEST_F(MacAudioInputTest, DISABLED_AUAudioInputStreamRecordToFile) {
291 if (!CanRunAudioTests())
292 return;
293 const char* file_name = "out_stereo_10sec.pcm";
295 int fs = static_cast<int>(AUAudioInputStream::HardwareSampleRate());
296 AudioInputStream* ais = CreateDefaultAudioInputStream();
297 EXPECT_TRUE(ais->Open());
299 fprintf(stderr, " File name : %s\n", file_name);
300 fprintf(stderr, " Sample rate: %d\n", fs);
301 WriteToFileAudioSink file_sink(file_name);
302 fprintf(stderr, " >> Speak into the mic while recording...\n");
303 ais->Start(&file_sink);
304 base::PlatformThread::Sleep(TestTimeouts::action_timeout());
305 ais->Stop();
306 fprintf(stderr, " >> Recording has stopped.\n");
307 ais->Close();
310 } // namespace media