cc: Added inline to Tile::IsReadyToDraw
[chromium-blink-merge.git] / media / audio / win / audio_low_latency_input_win_unittest.cc
blob40990ec13d4633f4ed94f38e563f39ebd22b6366
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 <windows.h>
6 #include <mmsystem.h>
8 #include "base/basictypes.h"
9 #include "base/environment.h"
10 #include "base/file_util.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/path_service.h"
14 #include "base/test/test_timeouts.h"
15 #include "base/win/scoped_com_initializer.h"
16 #include "media/audio/audio_io.h"
17 #include "media/audio/audio_manager_base.h"
18 #include "media/audio/win/audio_low_latency_input_win.h"
19 #include "media/audio/win/core_audio_util_win.h"
20 #include "media/base/seekable_buffer.h"
21 #include "testing/gmock/include/gmock/gmock.h"
22 #include "testing/gtest/include/gtest/gtest.h"
24 using base::win::ScopedCOMInitializer;
25 using ::testing::_;
26 using ::testing::AnyNumber;
27 using ::testing::AtLeast;
28 using ::testing::Gt;
29 using ::testing::NotNull;
31 namespace media {
33 ACTION_P3(CheckCountAndPostQuitTask, count, limit, loop) {
34 if (++*count >= limit) {
35 loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
39 class MockAudioInputCallback : public AudioInputStream::AudioInputCallback {
40 public:
41 MOCK_METHOD5(OnData, void(AudioInputStream* stream,
42 const uint8* src, uint32 size,
43 uint32 hardware_delay_bytes, double volume));
44 MOCK_METHOD1(OnClose, void(AudioInputStream* stream));
45 MOCK_METHOD1(OnError, void(AudioInputStream* stream));
48 // This audio sink implementation should be used for manual tests only since
49 // the recorded data is stored on a raw binary data file.
50 class WriteToFileAudioSink : public AudioInputStream::AudioInputCallback {
51 public:
52 // Allocate space for ~10 seconds of data @ 48kHz in stereo:
53 // 2 bytes per sample, 2 channels, 10ms @ 48kHz, 10 seconds <=> 1920000 bytes.
54 static const size_t kMaxBufferSize = 2 * 2 * 480 * 100 * 10;
56 explicit WriteToFileAudioSink(const char* file_name)
57 : buffer_(0, kMaxBufferSize),
58 bytes_to_write_(0) {
59 base::FilePath file_path;
60 EXPECT_TRUE(PathService::Get(base::DIR_EXE, &file_path));
61 file_path = file_path.AppendASCII(file_name);
62 binary_file_ = file_util::OpenFile(file_path, "wb");
63 DLOG_IF(ERROR, !binary_file_) << "Failed to open binary PCM data file.";
64 LOG(INFO) << ">> Output file: " << file_path.value()
65 << " has been created.";
68 virtual ~WriteToFileAudioSink() {
69 size_t bytes_written = 0;
70 while (bytes_written < bytes_to_write_) {
71 const uint8* chunk;
72 int chunk_size;
74 // Stop writing if no more data is available.
75 if (!buffer_.GetCurrentChunk(&chunk, &chunk_size))
76 break;
78 // Write recorded data chunk to the file and prepare for next chunk.
79 fwrite(chunk, 1, chunk_size, binary_file_);
80 buffer_.Seek(chunk_size);
81 bytes_written += chunk_size;
83 file_util::CloseFile(binary_file_);
86 // AudioInputStream::AudioInputCallback implementation.
87 virtual void OnData(AudioInputStream* stream,
88 const uint8* src,
89 uint32 size,
90 uint32 hardware_delay_bytes,
91 double volume) {
92 // Store data data in a temporary buffer to avoid making blocking
93 // fwrite() calls in the audio callback. The complete buffer will be
94 // written to file in the destructor.
95 if (buffer_.Append(src, size)) {
96 bytes_to_write_ += size;
100 virtual void OnClose(AudioInputStream* stream) {}
101 virtual void OnError(AudioInputStream* stream) {}
103 private:
104 media::SeekableBuffer buffer_;
105 FILE* binary_file_;
106 size_t bytes_to_write_;
109 // Convenience method which ensures that we are not running on the build
110 // bots and that at least one valid input device can be found. We also
111 // verify that we are not running on XP since the low-latency (WASAPI-
112 // based) version requires Windows Vista or higher.
113 static bool CanRunAudioTests(AudioManager* audio_man) {
114 if (!CoreAudioUtil::IsSupported()) {
115 LOG(WARNING) << "This tests requires Windows Vista or higher.";
116 return false;
118 // TODO(henrika): note that we use Wave today to query the number of
119 // existing input devices.
120 bool input = audio_man->HasAudioInputDevices();
121 LOG_IF(WARNING, !input) << "No input device detected.";
122 return input;
125 // Convenience method which creates a default AudioInputStream object but
126 // also allows the user to modify the default settings.
127 class AudioInputStreamWrapper {
128 public:
129 explicit AudioInputStreamWrapper(AudioManager* audio_manager)
130 : com_init_(ScopedCOMInitializer::kMTA),
131 audio_man_(audio_manager),
132 format_(AudioParameters::AUDIO_PCM_LOW_LATENCY),
133 channel_layout_(CHANNEL_LAYOUT_STEREO),
134 bits_per_sample_(16) {
135 // Use native/mixing sample rate and 10ms frame size as default.
136 sample_rate_ = static_cast<int>(
137 WASAPIAudioInputStream::HardwareSampleRate(
138 AudioManagerBase::kDefaultDeviceId));
139 samples_per_packet_ = sample_rate_ / 100;
142 ~AudioInputStreamWrapper() {}
144 // Creates AudioInputStream object using default parameters.
145 AudioInputStream* Create() {
146 return CreateInputStream();
149 // Creates AudioInputStream object using non-default parameters where the
150 // frame size is modified.
151 AudioInputStream* Create(int samples_per_packet) {
152 samples_per_packet_ = samples_per_packet;
153 return CreateInputStream();
156 AudioParameters::Format format() const { return format_; }
157 int channels() const {
158 return ChannelLayoutToChannelCount(channel_layout_);
160 int bits_per_sample() const { return bits_per_sample_; }
161 int sample_rate() const { return sample_rate_; }
162 int samples_per_packet() const { return samples_per_packet_; }
164 private:
165 AudioInputStream* CreateInputStream() {
166 AudioInputStream* ais = audio_man_->MakeAudioInputStream(
167 AudioParameters(format_, channel_layout_, sample_rate_,
168 bits_per_sample_, samples_per_packet_),
169 AudioManagerBase::kDefaultDeviceId);
170 EXPECT_TRUE(ais);
171 return ais;
174 ScopedCOMInitializer com_init_;
175 AudioManager* audio_man_;
176 AudioParameters::Format format_;
177 ChannelLayout channel_layout_;
178 int bits_per_sample_;
179 int sample_rate_;
180 int samples_per_packet_;
183 // Convenience method which creates a default AudioInputStream object.
184 static AudioInputStream* CreateDefaultAudioInputStream(
185 AudioManager* audio_manager) {
186 AudioInputStreamWrapper aisw(audio_manager);
187 AudioInputStream* ais = aisw.Create();
188 return ais;
191 // Verify that we can retrieve the current hardware/mixing sample rate
192 // for all available input devices.
193 TEST(WinAudioInputTest, WASAPIAudioInputStreamHardwareSampleRate) {
194 scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
195 if (!CanRunAudioTests(audio_manager.get()))
196 return;
198 ScopedCOMInitializer com_init(ScopedCOMInitializer::kMTA);
200 // Retrieve a list of all available input devices.
201 media::AudioDeviceNames device_names;
202 audio_manager->GetAudioInputDeviceNames(&device_names);
204 // Scan all available input devices and repeat the same test for all of them.
205 for (media::AudioDeviceNames::const_iterator it = device_names.begin();
206 it != device_names.end(); ++it) {
207 // Retrieve the hardware sample rate given a specified audio input device.
208 // TODO(tommi): ensure that we don't have to cast here.
209 int fs = static_cast<int>(WASAPIAudioInputStream::HardwareSampleRate(
210 it->unique_id));
211 EXPECT_GE(fs, 0);
215 // Test Create(), Close() calling sequence.
216 TEST(WinAudioInputTest, WASAPIAudioInputStreamCreateAndClose) {
217 scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
218 if (!CanRunAudioTests(audio_manager.get()))
219 return;
220 AudioInputStream* ais = CreateDefaultAudioInputStream(audio_manager.get());
221 ais->Close();
224 // Test Open(), Close() calling sequence.
225 TEST(WinAudioInputTest, WASAPIAudioInputStreamOpenAndClose) {
226 scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
227 if (!CanRunAudioTests(audio_manager.get()))
228 return;
229 AudioInputStream* ais = CreateDefaultAudioInputStream(audio_manager.get());
230 EXPECT_TRUE(ais->Open());
231 ais->Close();
234 // Test Open(), Start(), Close() calling sequence.
235 TEST(WinAudioInputTest, WASAPIAudioInputStreamOpenStartAndClose) {
236 scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
237 if (!CanRunAudioTests(audio_manager.get()))
238 return;
239 AudioInputStream* ais = CreateDefaultAudioInputStream(audio_manager.get());
240 EXPECT_TRUE(ais->Open());
241 MockAudioInputCallback sink;
242 ais->Start(&sink);
243 EXPECT_CALL(sink, OnClose(ais))
244 .Times(1);
245 ais->Close();
248 // Test Open(), Start(), Stop(), Close() calling sequence.
249 TEST(WinAudioInputTest, WASAPIAudioInputStreamOpenStartStopAndClose) {
250 scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
251 if (!CanRunAudioTests(audio_manager.get()))
252 return;
253 AudioInputStream* ais = CreateDefaultAudioInputStream(audio_manager.get());
254 EXPECT_TRUE(ais->Open());
255 MockAudioInputCallback sink;
256 ais->Start(&sink);
257 ais->Stop();
258 EXPECT_CALL(sink, OnClose(ais))
259 .Times(1);
260 ais->Close();
263 // Test some additional calling sequences.
264 TEST(WinAudioInputTest, WASAPIAudioInputStreamMiscCallingSequences) {
265 scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
266 if (!CanRunAudioTests(audio_manager.get()))
267 return;
268 AudioInputStream* ais = CreateDefaultAudioInputStream(audio_manager.get());
269 WASAPIAudioInputStream* wais = static_cast<WASAPIAudioInputStream*>(ais);
271 // Open(), Open() should fail the second time.
272 EXPECT_TRUE(ais->Open());
273 EXPECT_FALSE(ais->Open());
275 MockAudioInputCallback sink;
277 // Start(), Start() is a valid calling sequence (second call does nothing).
278 ais->Start(&sink);
279 EXPECT_TRUE(wais->started());
280 ais->Start(&sink);
281 EXPECT_TRUE(wais->started());
283 // Stop(), Stop() is a valid calling sequence (second call does nothing).
284 ais->Stop();
285 EXPECT_FALSE(wais->started());
286 ais->Stop();
287 EXPECT_FALSE(wais->started());
289 EXPECT_CALL(sink, OnClose(ais))
290 .Times(1);
291 ais->Close();
294 TEST(WinAudioInputTest, WASAPIAudioInputStreamTestPacketSizes) {
295 scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
296 if (!CanRunAudioTests(audio_manager.get()))
297 return;
299 int count = 0;
300 base::MessageLoopForUI loop;
302 // 10 ms packet size.
304 // Create default WASAPI input stream which records in stereo using
305 // the shared mixing rate. The default buffer size is 10ms.
306 AudioInputStreamWrapper aisw(audio_manager.get());
307 AudioInputStream* ais = aisw.Create();
308 EXPECT_TRUE(ais->Open());
310 MockAudioInputCallback sink;
312 // Derive the expected size in bytes of each recorded packet.
313 uint32 bytes_per_packet = aisw.channels() * aisw.samples_per_packet() *
314 (aisw.bits_per_sample() / 8);
316 // We use 10ms packets and will run the test until ten packets are received.
317 // All should contain valid packets of the same size and a valid delay
318 // estimate.
319 EXPECT_CALL(sink, OnData(
320 ais, NotNull(), bytes_per_packet, Gt(bytes_per_packet), _))
321 .Times(AtLeast(10))
322 .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop));
323 ais->Start(&sink);
324 loop.Run();
325 ais->Stop();
327 // Store current packet size (to be used in the subsequent tests).
328 int samples_per_packet_10ms = aisw.samples_per_packet();
330 EXPECT_CALL(sink, OnClose(ais))
331 .Times(1);
332 ais->Close();
334 // 20 ms packet size.
336 count = 0;
337 ais = aisw.Create(2 * samples_per_packet_10ms);
338 EXPECT_TRUE(ais->Open());
339 bytes_per_packet = aisw.channels() * aisw.samples_per_packet() *
340 (aisw.bits_per_sample() / 8);
342 EXPECT_CALL(sink, OnData(
343 ais, NotNull(), bytes_per_packet, Gt(bytes_per_packet), _))
344 .Times(AtLeast(10))
345 .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop));
346 ais->Start(&sink);
347 loop.Run();
348 ais->Stop();
350 EXPECT_CALL(sink, OnClose(ais))
351 .Times(1);
352 ais->Close();
354 // 5 ms packet size.
356 count = 0;
357 ais = aisw.Create(samples_per_packet_10ms / 2);
358 EXPECT_TRUE(ais->Open());
359 bytes_per_packet = aisw.channels() * aisw.samples_per_packet() *
360 (aisw.bits_per_sample() / 8);
362 EXPECT_CALL(sink, OnData(
363 ais, NotNull(), bytes_per_packet, Gt(bytes_per_packet), _))
364 .Times(AtLeast(10))
365 .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop));
366 ais->Start(&sink);
367 loop.Run();
368 ais->Stop();
370 EXPECT_CALL(sink, OnClose(ais))
371 .Times(1);
372 ais->Close();
375 // This test is intended for manual tests and should only be enabled
376 // when it is required to store the captured data on a local file.
377 // By default, GTest will print out YOU HAVE 1 DISABLED TEST.
378 // To include disabled tests in test execution, just invoke the test program
379 // with --gtest_also_run_disabled_tests or set the GTEST_ALSO_RUN_DISABLED_TESTS
380 // environment variable to a value greater than 0.
381 TEST(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamRecordToFile) {
382 scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
383 if (!CanRunAudioTests(audio_manager.get()))
384 return;
386 // Name of the output PCM file containing captured data. The output file
387 // will be stored in the directory containing 'media_unittests.exe'.
388 // Example of full name: \src\build\Debug\out_stereo_10sec.pcm.
389 const char* file_name = "out_stereo_10sec.pcm";
391 AudioInputStreamWrapper aisw(audio_manager.get());
392 AudioInputStream* ais = aisw.Create();
393 EXPECT_TRUE(ais->Open());
395 LOG(INFO) << ">> Sample rate: " << aisw.sample_rate() << " [Hz]";
396 WriteToFileAudioSink file_sink(file_name);
397 LOG(INFO) << ">> Speak into the default microphone while recording.";
398 ais->Start(&file_sink);
399 base::PlatformThread::Sleep(TestTimeouts::action_timeout());
400 ais->Stop();
401 LOG(INFO) << ">> Recording has stopped.";
402 ais->Close();
405 } // namespace media