Removed unused VideoCaptureCapability parameters.
[chromium-blink-merge.git] / media / audio / win / audio_low_latency_input_win_unittest.cc
blob11fad25d3febe4f44b895aa9a8f77e2289cac1c6
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 class FakeAudioInputCallback : public AudioInputStream::AudioInputCallback {
49 public:
50 FakeAudioInputCallback()
51 : closed_(false),
52 error_(false),
53 data_event_(false, false) {
56 const std::vector<uint8>& received_data() const { return received_data_; }
57 bool closed() const { return closed_; }
58 bool error() const { return error_; }
60 // Waits until OnData() is called on another thread.
61 void WaitForData() {
62 data_event_.Wait();
65 virtual void OnData(AudioInputStream* stream,
66 const uint8* src, uint32 size,
67 uint32 hardware_delay_bytes, double volume) OVERRIDE {
68 received_data_.insert(received_data_.end(), src, src + size);
69 data_event_.Signal();
72 virtual void OnClose(AudioInputStream* stream) OVERRIDE {
73 closed_ = true;
76 virtual void OnError(AudioInputStream* stream) OVERRIDE {
77 error_ = true;
80 private:
81 std::vector<uint8> received_data_;
82 base::WaitableEvent data_event_;
83 bool closed_;
84 bool error_;
86 DISALLOW_COPY_AND_ASSIGN(FakeAudioInputCallback);
89 // This audio sink implementation should be used for manual tests only since
90 // the recorded data is stored on a raw binary data file.
91 class WriteToFileAudioSink : public AudioInputStream::AudioInputCallback {
92 public:
93 // Allocate space for ~10 seconds of data @ 48kHz in stereo:
94 // 2 bytes per sample, 2 channels, 10ms @ 48kHz, 10 seconds <=> 1920000 bytes.
95 static const size_t kMaxBufferSize = 2 * 2 * 480 * 100 * 10;
97 explicit WriteToFileAudioSink(const char* file_name)
98 : buffer_(0, kMaxBufferSize),
99 bytes_to_write_(0) {
100 base::FilePath file_path;
101 EXPECT_TRUE(PathService::Get(base::DIR_EXE, &file_path));
102 file_path = file_path.AppendASCII(file_name);
103 binary_file_ = file_util::OpenFile(file_path, "wb");
104 DLOG_IF(ERROR, !binary_file_) << "Failed to open binary PCM data file.";
105 LOG(INFO) << ">> Output file: " << file_path.value()
106 << " has been created.";
109 virtual ~WriteToFileAudioSink() {
110 size_t bytes_written = 0;
111 while (bytes_written < bytes_to_write_) {
112 const uint8* chunk;
113 int chunk_size;
115 // Stop writing if no more data is available.
116 if (!buffer_.GetCurrentChunk(&chunk, &chunk_size))
117 break;
119 // Write recorded data chunk to the file and prepare for next chunk.
120 fwrite(chunk, 1, chunk_size, binary_file_);
121 buffer_.Seek(chunk_size);
122 bytes_written += chunk_size;
124 file_util::CloseFile(binary_file_);
127 // AudioInputStream::AudioInputCallback implementation.
128 virtual void OnData(AudioInputStream* stream,
129 const uint8* src,
130 uint32 size,
131 uint32 hardware_delay_bytes,
132 double volume) {
133 // Store data data in a temporary buffer to avoid making blocking
134 // fwrite() calls in the audio callback. The complete buffer will be
135 // written to file in the destructor.
136 if (buffer_.Append(src, size)) {
137 bytes_to_write_ += size;
141 virtual void OnClose(AudioInputStream* stream) {}
142 virtual void OnError(AudioInputStream* stream) {}
144 private:
145 media::SeekableBuffer buffer_;
146 FILE* binary_file_;
147 size_t bytes_to_write_;
150 // Convenience method which ensures that we are not running on the build
151 // bots and that at least one valid input device can be found. We also
152 // verify that we are not running on XP since the low-latency (WASAPI-
153 // based) version requires Windows Vista or higher.
154 static bool CanRunAudioTests(AudioManager* audio_man) {
155 if (!CoreAudioUtil::IsSupported()) {
156 LOG(WARNING) << "This tests requires Windows Vista or higher.";
157 return false;
159 // TODO(henrika): note that we use Wave today to query the number of
160 // existing input devices.
161 bool input = audio_man->HasAudioInputDevices();
162 LOG_IF(WARNING, !input) << "No input device detected.";
163 return input;
166 // Convenience method which creates a default AudioInputStream object but
167 // also allows the user to modify the default settings.
168 class AudioInputStreamWrapper {
169 public:
170 explicit AudioInputStreamWrapper(AudioManager* audio_manager)
171 : com_init_(ScopedCOMInitializer::kMTA),
172 audio_man_(audio_manager),
173 format_(AudioParameters::AUDIO_PCM_LOW_LATENCY),
174 channel_layout_(CHANNEL_LAYOUT_STEREO),
175 bits_per_sample_(16) {
176 // Use native/mixing sample rate and 10ms frame size as default.
177 sample_rate_ = static_cast<int>(
178 WASAPIAudioInputStream::HardwareSampleRate(
179 AudioManagerBase::kDefaultDeviceId));
180 samples_per_packet_ = sample_rate_ / 100;
183 ~AudioInputStreamWrapper() {}
185 // Creates AudioInputStream object using default parameters.
186 AudioInputStream* Create() {
187 return CreateInputStream();
190 // Creates AudioInputStream object using non-default parameters where the
191 // frame size is modified.
192 AudioInputStream* Create(int samples_per_packet) {
193 samples_per_packet_ = samples_per_packet;
194 return CreateInputStream();
197 AudioParameters::Format format() const { return format_; }
198 int channels() const {
199 return ChannelLayoutToChannelCount(channel_layout_);
201 int bits_per_sample() const { return bits_per_sample_; }
202 int sample_rate() const { return sample_rate_; }
203 int samples_per_packet() const { return samples_per_packet_; }
205 private:
206 AudioInputStream* CreateInputStream() {
207 AudioInputStream* ais = audio_man_->MakeAudioInputStream(
208 AudioParameters(format_, channel_layout_, sample_rate_,
209 bits_per_sample_, samples_per_packet_),
210 AudioManagerBase::kDefaultDeviceId);
211 EXPECT_TRUE(ais);
212 return ais;
215 ScopedCOMInitializer com_init_;
216 AudioManager* audio_man_;
217 AudioParameters::Format format_;
218 ChannelLayout channel_layout_;
219 int bits_per_sample_;
220 int sample_rate_;
221 int samples_per_packet_;
224 // Convenience method which creates a default AudioInputStream object.
225 static AudioInputStream* CreateDefaultAudioInputStream(
226 AudioManager* audio_manager) {
227 AudioInputStreamWrapper aisw(audio_manager);
228 AudioInputStream* ais = aisw.Create();
229 return ais;
232 class ScopedAudioInputStream {
233 public:
234 explicit ScopedAudioInputStream(AudioInputStream* stream)
235 : stream_(stream) {}
237 ~ScopedAudioInputStream() {
238 if (stream_)
239 stream_->Close();
242 void Close() {
243 if (stream_)
244 stream_->Close();
245 stream_ = NULL;
248 AudioInputStream* operator->() {
249 return stream_;
252 AudioInputStream* get() const { return stream_; }
254 void Reset(AudioInputStream* new_stream) {
255 Close();
256 stream_ = new_stream;
259 private:
260 AudioInputStream* stream_;
262 DISALLOW_COPY_AND_ASSIGN(ScopedAudioInputStream);
265 // Verify that we can retrieve the current hardware/mixing sample rate
266 // for all available input devices.
267 TEST(WinAudioInputTest, WASAPIAudioInputStreamHardwareSampleRate) {
268 scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
269 if (!CanRunAudioTests(audio_manager.get()))
270 return;
272 ScopedCOMInitializer com_init(ScopedCOMInitializer::kMTA);
274 // Retrieve a list of all available input devices.
275 media::AudioDeviceNames device_names;
276 audio_manager->GetAudioInputDeviceNames(&device_names);
278 // Scan all available input devices and repeat the same test for all of them.
279 for (media::AudioDeviceNames::const_iterator it = device_names.begin();
280 it != device_names.end(); ++it) {
281 // Retrieve the hardware sample rate given a specified audio input device.
282 // TODO(tommi): ensure that we don't have to cast here.
283 int fs = static_cast<int>(WASAPIAudioInputStream::HardwareSampleRate(
284 it->unique_id));
285 EXPECT_GE(fs, 0);
289 // Test Create(), Close() calling sequence.
290 TEST(WinAudioInputTest, WASAPIAudioInputStreamCreateAndClose) {
291 scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
292 if (!CanRunAudioTests(audio_manager.get()))
293 return;
294 ScopedAudioInputStream ais(
295 CreateDefaultAudioInputStream(audio_manager.get()));
296 ais.Close();
299 // Test Open(), Close() calling sequence.
300 TEST(WinAudioInputTest, WASAPIAudioInputStreamOpenAndClose) {
301 scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
302 if (!CanRunAudioTests(audio_manager.get()))
303 return;
304 ScopedAudioInputStream ais(
305 CreateDefaultAudioInputStream(audio_manager.get()));
306 EXPECT_TRUE(ais->Open());
307 ais.Close();
310 // Test Open(), Start(), Close() calling sequence.
311 TEST(WinAudioInputTest, WASAPIAudioInputStreamOpenStartAndClose) {
312 scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
313 if (!CanRunAudioTests(audio_manager.get()))
314 return;
315 ScopedAudioInputStream ais(
316 CreateDefaultAudioInputStream(audio_manager.get()));
317 EXPECT_TRUE(ais->Open());
318 MockAudioInputCallback sink;
319 ais->Start(&sink);
320 EXPECT_CALL(sink, OnClose(ais.get()))
321 .Times(1);
322 ais.Close();
325 // Test Open(), Start(), Stop(), Close() calling sequence.
326 TEST(WinAudioInputTest, WASAPIAudioInputStreamOpenStartStopAndClose) {
327 scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
328 if (!CanRunAudioTests(audio_manager.get()))
329 return;
330 ScopedAudioInputStream ais(
331 CreateDefaultAudioInputStream(audio_manager.get()));
332 EXPECT_TRUE(ais->Open());
333 MockAudioInputCallback sink;
334 ais->Start(&sink);
335 ais->Stop();
336 EXPECT_CALL(sink, OnClose(ais.get()))
337 .Times(1);
338 ais.Close();
341 // Test some additional calling sequences.
342 TEST(WinAudioInputTest, WASAPIAudioInputStreamMiscCallingSequences) {
343 scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
344 if (!CanRunAudioTests(audio_manager.get()))
345 return;
346 ScopedAudioInputStream ais(
347 CreateDefaultAudioInputStream(audio_manager.get()));
348 WASAPIAudioInputStream* wais =
349 static_cast<WASAPIAudioInputStream*>(ais.get());
351 // Open(), Open() should fail the second time.
352 EXPECT_TRUE(ais->Open());
353 EXPECT_FALSE(ais->Open());
355 MockAudioInputCallback sink;
357 // Start(), Start() is a valid calling sequence (second call does nothing).
358 ais->Start(&sink);
359 EXPECT_TRUE(wais->started());
360 ais->Start(&sink);
361 EXPECT_TRUE(wais->started());
363 // Stop(), Stop() is a valid calling sequence (second call does nothing).
364 ais->Stop();
365 EXPECT_FALSE(wais->started());
366 ais->Stop();
367 EXPECT_FALSE(wais->started());
369 EXPECT_CALL(sink, OnClose(ais.get()))
370 .Times(1);
371 ais.Close();
374 TEST(WinAudioInputTest, WASAPIAudioInputStreamTestPacketSizes) {
375 scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
376 if (!CanRunAudioTests(audio_manager.get()))
377 return;
379 int count = 0;
380 base::MessageLoopForUI loop;
382 // 10 ms packet size.
384 // Create default WASAPI input stream which records in stereo using
385 // the shared mixing rate. The default buffer size is 10ms.
386 AudioInputStreamWrapper aisw(audio_manager.get());
387 ScopedAudioInputStream ais(aisw.Create());
388 EXPECT_TRUE(ais->Open());
390 MockAudioInputCallback sink;
392 // Derive the expected size in bytes of each recorded packet.
393 uint32 bytes_per_packet = aisw.channels() * aisw.samples_per_packet() *
394 (aisw.bits_per_sample() / 8);
396 // We use 10ms packets and will run the test until ten packets are received.
397 // All should contain valid packets of the same size and a valid delay
398 // estimate.
399 EXPECT_CALL(sink, OnData(
400 ais.get(), NotNull(), bytes_per_packet, Gt(bytes_per_packet), _))
401 .Times(AtLeast(10))
402 .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop));
403 ais->Start(&sink);
404 loop.Run();
405 ais->Stop();
407 // Store current packet size (to be used in the subsequent tests).
408 int samples_per_packet_10ms = aisw.samples_per_packet();
410 EXPECT_CALL(sink, OnClose(ais.get()))
411 .Times(1);
412 ais.Close();
414 // 20 ms packet size.
416 count = 0;
417 ais.Reset(aisw.Create(2 * samples_per_packet_10ms));
418 EXPECT_TRUE(ais->Open());
419 bytes_per_packet = aisw.channels() * aisw.samples_per_packet() *
420 (aisw.bits_per_sample() / 8);
422 EXPECT_CALL(sink, OnData(
423 ais.get(), NotNull(), bytes_per_packet, Gt(bytes_per_packet), _))
424 .Times(AtLeast(10))
425 .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop));
426 ais->Start(&sink);
427 loop.Run();
428 ais->Stop();
430 EXPECT_CALL(sink, OnClose(ais.get()))
431 .Times(1);
432 ais.Close();
434 // 5 ms packet size.
436 count = 0;
437 ais.Reset(aisw.Create(samples_per_packet_10ms / 2));
438 EXPECT_TRUE(ais->Open());
439 bytes_per_packet = aisw.channels() * aisw.samples_per_packet() *
440 (aisw.bits_per_sample() / 8);
442 EXPECT_CALL(sink, OnData(
443 ais.get(), NotNull(), bytes_per_packet, Gt(bytes_per_packet), _))
444 .Times(AtLeast(10))
445 .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop));
446 ais->Start(&sink);
447 loop.Run();
448 ais->Stop();
450 EXPECT_CALL(sink, OnClose(ais.get()))
451 .Times(1);
452 ais.Close();
455 // Test that we can capture loopback stream.
456 TEST(WinAudioInputTest, WASAPIAudioInputStreamLoopback) {
457 scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
458 if (!audio_manager->HasAudioOutputDevices() || !CoreAudioUtil::IsSupported())
459 return;
461 AudioParameters params = audio_manager->GetInputStreamParameters(
462 AudioManagerBase::kLoopbackInputDeviceId);
464 AudioParameters output_params =
465 audio_manager->GetOutputStreamParameters(std::string());
466 EXPECT_EQ(params.sample_rate(), output_params.sample_rate());
467 EXPECT_EQ(params.channel_layout(), output_params.channel_layout());
469 ScopedAudioInputStream stream(audio_manager->MakeAudioInputStream(
470 params, AudioManagerBase::kLoopbackInputDeviceId));
471 ASSERT_TRUE(stream->Open());
472 FakeAudioInputCallback sink;
473 stream->Start(&sink);
474 ASSERT_FALSE(sink.error());
476 sink.WaitForData();
477 stream.Close();
479 EXPECT_FALSE(sink.received_data().empty());
480 EXPECT_TRUE(sink.closed());
481 EXPECT_FALSE(sink.error());
484 // This test is intended for manual tests and should only be enabled
485 // when it is required to store the captured data on a local file.
486 // By default, GTest will print out YOU HAVE 1 DISABLED TEST.
487 // To include disabled tests in test execution, just invoke the test program
488 // with --gtest_also_run_disabled_tests or set the GTEST_ALSO_RUN_DISABLED_TESTS
489 // environment variable to a value greater than 0.
490 TEST(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamRecordToFile) {
491 scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
492 if (!CanRunAudioTests(audio_manager.get()))
493 return;
495 // Name of the output PCM file containing captured data. The output file
496 // will be stored in the directory containing 'media_unittests.exe'.
497 // Example of full name: \src\build\Debug\out_stereo_10sec.pcm.
498 const char* file_name = "out_stereo_10sec.pcm";
500 AudioInputStreamWrapper aisw(audio_manager.get());
501 ScopedAudioInputStream ais(aisw.Create());
502 EXPECT_TRUE(ais->Open());
504 LOG(INFO) << ">> Sample rate: " << aisw.sample_rate() << " [Hz]";
505 WriteToFileAudioSink file_sink(file_name);
506 LOG(INFO) << ">> Speak into the default microphone while recording.";
507 ais->Start(&file_sink);
508 base::PlatformThread::Sleep(TestTimeouts::action_timeout());
509 ais->Stop();
510 LOG(INFO) << ">> Recording has stopped.";
511 ais.Close();
514 } // namespace media