Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / media / audio / win / audio_low_latency_input_win_unittest.cc
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.
4
5 #include <windows.h>
6 #include <mmsystem.h>
7
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"
23
24 using base::win::ScopedCOMInitializer;
25 using ::testing::_;
26 using ::testing::AnyNumber;
27 using ::testing::AtLeast;
28 using ::testing::Gt;
29 using ::testing::NotNull;
30
31 namespace media {
32
33 ACTION_P3(CheckCountAndPostQuitTask, count, limit, loop) {
34   if (++*count >= limit) {
35     loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
36   }
37 }
38
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(OnError, void(AudioInputStream* stream));
45 };
46
47 class FakeAudioInputCallback : public AudioInputStream::AudioInputCallback {
48  public:
49   FakeAudioInputCallback()
50     : error_(false),
51       data_event_(false, false) {
52   }
53
54   const std::vector<uint8>& received_data() const { return received_data_; }
55   bool error() const { return error_; }
56
57   // Waits until OnData() is called on another thread.
58   void WaitForData() {
59     data_event_.Wait();
60   }
61
62   virtual void OnData(AudioInputStream* stream,
63                       const uint8* src, uint32 size,
64                       uint32 hardware_delay_bytes, double volume) OVERRIDE {
65     received_data_.insert(received_data_.end(), src, src + size);
66     data_event_.Signal();
67   }
68
69   virtual void OnError(AudioInputStream* stream) OVERRIDE {
70     error_ = true;
71   }
72
73  private:
74   std::vector<uint8> received_data_;
75   base::WaitableEvent data_event_;
76   bool error_;
77
78   DISALLOW_COPY_AND_ASSIGN(FakeAudioInputCallback);
79 };
80
81 // This audio sink implementation should be used for manual tests only since
82 // the recorded data is stored on a raw binary data file.
83 class WriteToFileAudioSink : public AudioInputStream::AudioInputCallback {
84  public:
85   // Allocate space for ~10 seconds of data @ 48kHz in stereo:
86   // 2 bytes per sample, 2 channels, 10ms @ 48kHz, 10 seconds <=> 1920000 bytes.
87   static const size_t kMaxBufferSize = 2 * 2 * 480 * 100 * 10;
88
89   explicit WriteToFileAudioSink(const char* file_name)
90       : buffer_(0, kMaxBufferSize),
91         bytes_to_write_(0) {
92     base::FilePath file_path;
93     EXPECT_TRUE(PathService::Get(base::DIR_EXE, &file_path));
94     file_path = file_path.AppendASCII(file_name);
95     binary_file_ = base::OpenFile(file_path, "wb");
96     DLOG_IF(ERROR, !binary_file_) << "Failed to open binary PCM data file.";
97     VLOG(0) << ">> Output file: " << file_path.value() << " has been created.";
98   }
99
100   virtual ~WriteToFileAudioSink() {
101     size_t bytes_written = 0;
102     while (bytes_written < bytes_to_write_) {
103       const uint8* chunk;
104       int chunk_size;
105
106       // Stop writing if no more data is available.
107       if (!buffer_.GetCurrentChunk(&chunk, &chunk_size))
108         break;
109
110       // Write recorded data chunk to the file and prepare for next chunk.
111       fwrite(chunk, 1, chunk_size, binary_file_);
112       buffer_.Seek(chunk_size);
113       bytes_written += chunk_size;
114     }
115     base::CloseFile(binary_file_);
116   }
117
118   // AudioInputStream::AudioInputCallback implementation.
119   virtual void OnData(AudioInputStream* stream,
120                       const uint8* src,
121                       uint32 size,
122                       uint32 hardware_delay_bytes,
123                       double volume) {
124     // Store data data in a temporary buffer to avoid making blocking
125     // fwrite() calls in the audio callback. The complete buffer will be
126     // written to file in the destructor.
127     if (buffer_.Append(src, size)) {
128       bytes_to_write_ += size;
129     }
130   }
131
132   virtual void OnError(AudioInputStream* stream) {}
133
134  private:
135   media::SeekableBuffer buffer_;
136   FILE* binary_file_;
137   size_t bytes_to_write_;
138 };
139
140 // Convenience method which ensures that we are not running on the build
141 // bots and that at least one valid input device can be found. We also
142 // verify that we are not running on XP since the low-latency (WASAPI-
143 // based) version requires Windows Vista or higher.
144 static bool CanRunAudioTests(AudioManager* audio_man) {
145   if (!CoreAudioUtil::IsSupported()) {
146     LOG(WARNING) << "This tests requires Windows Vista or higher.";
147     return false;
148   }
149   // TODO(henrika): note that we use Wave today to query the number of
150   // existing input devices.
151   bool input = audio_man->HasAudioInputDevices();
152   LOG_IF(WARNING, !input) << "No input device detected.";
153   return input;
154 }
155
156 // Convenience method which creates a default AudioInputStream object but
157 // also allows the user to modify the default settings.
158 class AudioInputStreamWrapper {
159  public:
160   explicit AudioInputStreamWrapper(AudioManager* audio_manager)
161       : com_init_(ScopedCOMInitializer::kMTA),
162         audio_man_(audio_manager),
163         default_params_(
164             audio_manager->GetInputStreamParameters(
165                   AudioManagerBase::kDefaultDeviceId)) {
166     EXPECT_EQ(format(), AudioParameters::AUDIO_PCM_LOW_LATENCY);
167     frames_per_buffer_ = default_params_.frames_per_buffer();
168     // We expect the default buffer size to be a 10ms buffer.
169     EXPECT_EQ(frames_per_buffer_, sample_rate() / 100);
170   }
171
172   ~AudioInputStreamWrapper() {}
173
174   // Creates AudioInputStream object using default parameters.
175   AudioInputStream* Create() {
176     return CreateInputStream();
177   }
178
179   // Creates AudioInputStream object using non-default parameters where the
180   // frame size is modified.
181   AudioInputStream* Create(int frames_per_buffer) {
182     frames_per_buffer_ = frames_per_buffer;
183     return CreateInputStream();
184   }
185
186   AudioParameters::Format format() const { return default_params_.format(); }
187   int channels() const {
188     return ChannelLayoutToChannelCount(default_params_.channel_layout());
189   }
190   int bits_per_sample() const { return default_params_.bits_per_sample(); }
191   int sample_rate() const { return default_params_.sample_rate(); }
192   int frames_per_buffer() const { return frames_per_buffer_; }
193
194  private:
195   AudioInputStream* CreateInputStream() {
196     AudioInputStream* ais = audio_man_->MakeAudioInputStream(
197         AudioParameters(format(), default_params_.channel_layout(),
198                         default_params_.input_channels(),
199                         sample_rate(), bits_per_sample(), frames_per_buffer_,
200                         default_params_.effects()),
201         AudioManagerBase::kDefaultDeviceId);
202     EXPECT_TRUE(ais);
203     return ais;
204   }
205
206   ScopedCOMInitializer com_init_;
207   AudioManager* audio_man_;
208   const AudioParameters default_params_;
209   int frames_per_buffer_;
210 };
211
212 // Convenience method which creates a default AudioInputStream object.
213 static AudioInputStream* CreateDefaultAudioInputStream(
214     AudioManager* audio_manager) {
215   AudioInputStreamWrapper aisw(audio_manager);
216   AudioInputStream* ais = aisw.Create();
217   return ais;
218 }
219
220 class ScopedAudioInputStream {
221  public:
222   explicit ScopedAudioInputStream(AudioInputStream* stream)
223       : stream_(stream) {}
224
225   ~ScopedAudioInputStream() {
226     if (stream_)
227       stream_->Close();
228   }
229
230   void Close() {
231     if (stream_)
232       stream_->Close();
233     stream_ = NULL;
234   }
235
236   AudioInputStream* operator->() {
237     return stream_;
238   }
239
240   AudioInputStream* get() const { return stream_; }
241
242   void Reset(AudioInputStream* new_stream) {
243     Close();
244     stream_ = new_stream;
245   }
246
247  private:
248   AudioInputStream* stream_;
249
250   DISALLOW_COPY_AND_ASSIGN(ScopedAudioInputStream);
251 };
252
253 // Verify that we can retrieve the current hardware/mixing sample rate
254 // for all available input devices.
255 TEST(WinAudioInputTest, WASAPIAudioInputStreamHardwareSampleRate) {
256   scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
257   if (!CanRunAudioTests(audio_manager.get()))
258     return;
259
260   ScopedCOMInitializer com_init(ScopedCOMInitializer::kMTA);
261
262   // Retrieve a list of all available input devices.
263   media::AudioDeviceNames device_names;
264   audio_manager->GetAudioInputDeviceNames(&device_names);
265
266   // Scan all available input devices and repeat the same test for all of them.
267   for (media::AudioDeviceNames::const_iterator it = device_names.begin();
268        it != device_names.end(); ++it) {
269     // Retrieve the hardware sample rate given a specified audio input device.
270     AudioParameters params = WASAPIAudioInputStream::GetInputStreamParameters(
271         it->unique_id);
272     EXPECT_GE(params.sample_rate(), 0);
273   }
274 }
275
276 // Test Create(), Close() calling sequence.
277 TEST(WinAudioInputTest, WASAPIAudioInputStreamCreateAndClose) {
278   scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
279   if (!CanRunAudioTests(audio_manager.get()))
280     return;
281   ScopedAudioInputStream ais(
282       CreateDefaultAudioInputStream(audio_manager.get()));
283   ais.Close();
284 }
285
286 // Test Open(), Close() calling sequence.
287 TEST(WinAudioInputTest, WASAPIAudioInputStreamOpenAndClose) {
288   scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
289   if (!CanRunAudioTests(audio_manager.get()))
290     return;
291   ScopedAudioInputStream ais(
292       CreateDefaultAudioInputStream(audio_manager.get()));
293   EXPECT_TRUE(ais->Open());
294   ais.Close();
295 }
296
297 // Test Open(), Start(), Close() calling sequence.
298 TEST(WinAudioInputTest, WASAPIAudioInputStreamOpenStartAndClose) {
299   scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
300   if (!CanRunAudioTests(audio_manager.get()))
301     return;
302   ScopedAudioInputStream ais(
303       CreateDefaultAudioInputStream(audio_manager.get()));
304   EXPECT_TRUE(ais->Open());
305   MockAudioInputCallback sink;
306   ais->Start(&sink);
307   ais.Close();
308 }
309
310 // Test Open(), Start(), Stop(), Close() calling sequence.
311 TEST(WinAudioInputTest, WASAPIAudioInputStreamOpenStartStopAndClose) {
312   scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
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   ais->Stop();
321   ais.Close();
322 }
323
324 // Test some additional calling sequences.
325 TEST(WinAudioInputTest, WASAPIAudioInputStreamMiscCallingSequences) {
326   scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
327   if (!CanRunAudioTests(audio_manager.get()))
328     return;
329   ScopedAudioInputStream ais(
330       CreateDefaultAudioInputStream(audio_manager.get()));
331   WASAPIAudioInputStream* wais =
332       static_cast<WASAPIAudioInputStream*>(ais.get());
333
334   // Open(), Open() should fail the second time.
335   EXPECT_TRUE(ais->Open());
336   EXPECT_FALSE(ais->Open());
337
338   MockAudioInputCallback sink;
339
340   // Start(), Start() is a valid calling sequence (second call does nothing).
341   ais->Start(&sink);
342   EXPECT_TRUE(wais->started());
343   ais->Start(&sink);
344   EXPECT_TRUE(wais->started());
345
346   // Stop(), Stop() is a valid calling sequence (second call does nothing).
347   ais->Stop();
348   EXPECT_FALSE(wais->started());
349   ais->Stop();
350   EXPECT_FALSE(wais->started());
351   ais.Close();
352 }
353
354 TEST(WinAudioInputTest, WASAPIAudioInputStreamTestPacketSizes) {
355   scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
356   if (!CanRunAudioTests(audio_manager.get()))
357     return;
358
359   int count = 0;
360   base::MessageLoopForUI loop;
361
362   // 10 ms packet size.
363
364   // Create default WASAPI input stream which records in stereo using
365   // the shared mixing rate. The default buffer size is 10ms.
366   AudioInputStreamWrapper aisw(audio_manager.get());
367   ScopedAudioInputStream ais(aisw.Create());
368   EXPECT_TRUE(ais->Open());
369
370   MockAudioInputCallback sink;
371
372   // Derive the expected size in bytes of each recorded packet.
373   uint32 bytes_per_packet = aisw.channels() * aisw.frames_per_buffer() *
374       (aisw.bits_per_sample() / 8);
375
376   // We use 10ms packets and will run the test until ten packets are received.
377   // All should contain valid packets of the same size and a valid delay
378   // estimate.
379   EXPECT_CALL(sink, OnData(
380       ais.get(), NotNull(), bytes_per_packet, Gt(bytes_per_packet), _))
381       .Times(AtLeast(10))
382       .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop));
383   ais->Start(&sink);
384   loop.Run();
385   ais->Stop();
386
387   // Store current packet size (to be used in the subsequent tests).
388   int frames_per_buffer_10ms = aisw.frames_per_buffer();
389
390   ais.Close();
391
392   // 20 ms packet size.
393
394   count = 0;
395   ais.Reset(aisw.Create(2 * frames_per_buffer_10ms));
396   EXPECT_TRUE(ais->Open());
397   bytes_per_packet = aisw.channels() * aisw.frames_per_buffer() *
398       (aisw.bits_per_sample() / 8);
399
400   EXPECT_CALL(sink, OnData(
401       ais.get(), NotNull(), bytes_per_packet, Gt(bytes_per_packet), _))
402       .Times(AtLeast(10))
403       .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop));
404   ais->Start(&sink);
405   loop.Run();
406   ais->Stop();
407   ais.Close();
408
409   // 5 ms packet size.
410
411   count = 0;
412   ais.Reset(aisw.Create(frames_per_buffer_10ms / 2));
413   EXPECT_TRUE(ais->Open());
414   bytes_per_packet = aisw.channels() * aisw.frames_per_buffer() *
415     (aisw.bits_per_sample() / 8);
416
417   EXPECT_CALL(sink, OnData(
418       ais.get(), NotNull(), bytes_per_packet, Gt(bytes_per_packet), _))
419       .Times(AtLeast(10))
420       .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop));
421   ais->Start(&sink);
422   loop.Run();
423   ais->Stop();
424   ais.Close();
425 }
426
427 // Test that we can capture loopback stream.
428 TEST(WinAudioInputTest, WASAPIAudioInputStreamLoopback) {
429   scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
430   if (!audio_manager->HasAudioOutputDevices() || !CoreAudioUtil::IsSupported())
431     return;
432
433   AudioParameters params = audio_manager->GetInputStreamParameters(
434       AudioManagerBase::kLoopbackInputDeviceId);
435   EXPECT_EQ(params.effects(), 0);
436
437   AudioParameters output_params =
438       audio_manager->GetOutputStreamParameters(std::string());
439   EXPECT_EQ(params.sample_rate(), output_params.sample_rate());
440   EXPECT_EQ(params.channel_layout(), output_params.channel_layout());
441
442   ScopedAudioInputStream stream(audio_manager->MakeAudioInputStream(
443       params, AudioManagerBase::kLoopbackInputDeviceId));
444   ASSERT_TRUE(stream->Open());
445   FakeAudioInputCallback sink;
446   stream->Start(&sink);
447   ASSERT_FALSE(sink.error());
448
449   sink.WaitForData();
450   stream.Close();
451
452   EXPECT_FALSE(sink.received_data().empty());
453   EXPECT_FALSE(sink.error());
454 }
455
456 // This test is intended for manual tests and should only be enabled
457 // when it is required to store the captured data on a local file.
458 // By default, GTest will print out YOU HAVE 1 DISABLED TEST.
459 // To include disabled tests in test execution, just invoke the test program
460 // with --gtest_also_run_disabled_tests or set the GTEST_ALSO_RUN_DISABLED_TESTS
461 // environment variable to a value greater than 0.
462 TEST(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamRecordToFile) {
463   scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
464   if (!CanRunAudioTests(audio_manager.get()))
465     return;
466
467   // Name of the output PCM file containing captured data. The output file
468   // will be stored in the directory containing 'media_unittests.exe'.
469   // Example of full name: \src\build\Debug\out_stereo_10sec.pcm.
470   const char* file_name = "out_stereo_10sec.pcm";
471
472   AudioInputStreamWrapper aisw(audio_manager.get());
473   ScopedAudioInputStream ais(aisw.Create());
474   EXPECT_TRUE(ais->Open());
475
476   VLOG(0) << ">> Sample rate: " << aisw.sample_rate() << " [Hz]";
477   WriteToFileAudioSink file_sink(file_name);
478   VLOG(0) << ">> Speak into the default microphone while recording.";
479   ais->Start(&file_sink);
480   base::PlatformThread::Sleep(TestTimeouts::action_timeout());
481   ais->Stop();
482   VLOG(0) << ">> Recording has stopped.";
483   ais.Close();
484 }
485
486 }  // namespace media