| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <windows.h> | 5 #include <windows.h> |
| 6 #include <mmsystem.h> | 6 #include <mmsystem.h> |
| 7 | 7 |
| 8 #include "base/basictypes.h" | 8 #include "base/basictypes.h" |
| 9 #include "base/environment.h" | 9 #include "base/environment.h" |
| 10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
| 11 #include "base/memory/scoped_ptr.h" | 11 #include "base/memory/scoped_ptr.h" |
| 12 #include "base/message_loop.h" | 12 #include "base/message_loop.h" |
| 13 #include "base/path_service.h" | 13 #include "base/path_service.h" |
| 14 #include "base/test/test_timeouts.h" | 14 #include "base/test/test_timeouts.h" |
| 15 #include "base/win/scoped_com_initializer.h" | 15 #include "base/win/scoped_com_initializer.h" |
| 16 #include "media/audio/audio_io.h" | 16 #include "media/audio/audio_io.h" |
| 17 #include "media/audio/audio_manager_base.h" | 17 #include "media/audio/audio_manager_base.h" |
| 18 #include "media/audio/win/audio_low_latency_input_win.h" | 18 #include "media/audio/win/audio_low_latency_input_win.h" |
| 19 #include "media/base/seekable_buffer.h" | 19 #include "media/base/seekable_buffer.h" |
| 20 #include "testing/gmock/include/gmock/gmock.h" | 20 #include "testing/gmock/include/gmock/gmock.h" |
| 21 #include "testing/gtest/include/gtest/gtest.h" | 21 #include "testing/gtest/include/gtest/gtest.h" |
| 22 | 22 |
| 23 using base::win::ScopedCOMInitializer; | 23 using base::win::ScopedCOMInitializer; |
| 24 using ::testing::_; |
| 24 using ::testing::AnyNumber; | 25 using ::testing::AnyNumber; |
| 25 using ::testing::AtLeast; | 26 using ::testing::AtLeast; |
| 26 using ::testing::Gt; | 27 using ::testing::Gt; |
| 27 using ::testing::NotNull; | 28 using ::testing::NotNull; |
| 28 | 29 |
| 29 ACTION_P3(CheckCountAndPostQuitTask, count, limit, loop) { | 30 ACTION_P3(CheckCountAndPostQuitTask, count, limit, loop) { |
| 30 if (++*count >= limit) { | 31 if (++*count >= limit) { |
| 31 loop->PostTask(FROM_HERE, MessageLoop::QuitClosure()); | 32 loop->PostTask(FROM_HERE, MessageLoop::QuitClosure()); |
| 32 } | 33 } |
| 33 } | 34 } |
| 34 | 35 |
| 35 class MockAudioInputCallback : public AudioInputStream::AudioInputCallback { | 36 class MockAudioInputCallback : public AudioInputStream::AudioInputCallback { |
| 36 public: | 37 public: |
| 37 MOCK_METHOD4(OnData, void(AudioInputStream* stream, | 38 MOCK_METHOD5(OnData, void(AudioInputStream* stream, |
| 38 const uint8* src, uint32 size, | 39 const uint8* src, uint32 size, |
| 39 uint32 hardware_delay_bytes)); | 40 uint32 hardware_delay_bytes, double volume)); |
| 40 MOCK_METHOD1(OnClose, void(AudioInputStream* stream)); | 41 MOCK_METHOD1(OnClose, void(AudioInputStream* stream)); |
| 41 MOCK_METHOD2(OnError, void(AudioInputStream* stream, int code)); | 42 MOCK_METHOD2(OnError, void(AudioInputStream* stream, int code)); |
| 42 }; | 43 }; |
| 43 | 44 |
| 44 // This audio sink implementation should be used for manual tests only since | 45 // This audio sink implementation should be used for manual tests only since |
| 45 // the recorded data is stored on a raw binary data file. | 46 // the recorded data is stored on a raw binary data file. |
| 46 class WriteToFileAudioSink : public AudioInputStream::AudioInputCallback { | 47 class WriteToFileAudioSink : public AudioInputStream::AudioInputCallback { |
| 47 public: | 48 public: |
| 48 // Allocate space for ~10 seconds of data @ 48kHz in stereo: | 49 // Allocate space for ~10 seconds of data @ 48kHz in stereo: |
| 49 // 2 bytes per sample, 2 channels, 10ms @ 48kHz, 10 seconds <=> 1920000 bytes. | 50 // 2 bytes per sample, 2 channels, 10ms @ 48kHz, 10 seconds <=> 1920000 bytes. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 76 buffer_.Seek(chunk_size); | 77 buffer_.Seek(chunk_size); |
| 77 bytes_written += chunk_size; | 78 bytes_written += chunk_size; |
| 78 } | 79 } |
| 79 file_util::CloseFile(binary_file_); | 80 file_util::CloseFile(binary_file_); |
| 80 } | 81 } |
| 81 | 82 |
| 82 // AudioInputStream::AudioInputCallback implementation. | 83 // AudioInputStream::AudioInputCallback implementation. |
| 83 virtual void OnData(AudioInputStream* stream, | 84 virtual void OnData(AudioInputStream* stream, |
| 84 const uint8* src, | 85 const uint8* src, |
| 85 uint32 size, | 86 uint32 size, |
| 86 uint32 hardware_delay_bytes) { | 87 uint32 hardware_delay_bytes, |
| 88 double volume) { |
| 87 // Store data data in a temporary buffer to avoid making blocking | 89 // Store data data in a temporary buffer to avoid making blocking |
| 88 // fwrite() calls in the audio callback. The complete buffer will be | 90 // fwrite() calls in the audio callback. The complete buffer will be |
| 89 // written to file in the destructor. | 91 // written to file in the destructor. |
| 90 if (buffer_.Append(src, size)) { | 92 if (buffer_.Append(src, size)) { |
| 91 bytes_to_write_ += size; | 93 bytes_to_write_ += size; |
| 92 } | 94 } |
| 93 } | 95 } |
| 94 | 96 |
| 95 virtual void OnClose(AudioInputStream* stream) {} | 97 virtual void OnClose(AudioInputStream* stream) {} |
| 96 virtual void OnError(AudioInputStream* stream, int code) {} | 98 virtual void OnError(AudioInputStream* stream, int code) {} |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 299 MockAudioInputCallback sink; | 301 MockAudioInputCallback sink; |
| 300 | 302 |
| 301 // Derive the expected size in bytes of each recorded packet. | 303 // Derive the expected size in bytes of each recorded packet. |
| 302 uint32 bytes_per_packet = aisw.channels() * aisw.samples_per_packet() * | 304 uint32 bytes_per_packet = aisw.channels() * aisw.samples_per_packet() * |
| 303 (aisw.bits_per_sample() / 8); | 305 (aisw.bits_per_sample() / 8); |
| 304 | 306 |
| 305 // We use 10ms packets and will run the test until ten packets are received. | 307 // We use 10ms packets and will run the test until ten packets are received. |
| 306 // All should contain valid packets of the same size and a valid delay | 308 // All should contain valid packets of the same size and a valid delay |
| 307 // estimate. | 309 // estimate. |
| 308 EXPECT_CALL(sink, OnData( | 310 EXPECT_CALL(sink, OnData( |
| 309 ais, NotNull(), bytes_per_packet, Gt(bytes_per_packet))) | 311 ais, NotNull(), bytes_per_packet, Gt(bytes_per_packet), _)) |
| 310 .Times(AtLeast(10)) | 312 .Times(AtLeast(10)) |
| 311 .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop)); | 313 .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop)); |
| 312 ais->Start(&sink); | 314 ais->Start(&sink); |
| 313 loop.Run(); | 315 loop.Run(); |
| 314 ais->Stop(); | 316 ais->Stop(); |
| 315 | 317 |
| 316 // Store current packet size (to be used in the subsequent tests). | 318 // Store current packet size (to be used in the subsequent tests). |
| 317 int samples_per_packet_10ms = aisw.samples_per_packet(); | 319 int samples_per_packet_10ms = aisw.samples_per_packet(); |
| 318 | 320 |
| 319 EXPECT_CALL(sink, OnClose(ais)) | 321 EXPECT_CALL(sink, OnClose(ais)) |
| 320 .Times(1); | 322 .Times(1); |
| 321 ais->Close(); | 323 ais->Close(); |
| 322 | 324 |
| 323 // 20 ms packet size. | 325 // 20 ms packet size. |
| 324 | 326 |
| 325 count = 0; | 327 count = 0; |
| 326 ais = aisw.Create(2 * samples_per_packet_10ms); | 328 ais = aisw.Create(2 * samples_per_packet_10ms); |
| 327 EXPECT_TRUE(ais->Open()); | 329 EXPECT_TRUE(ais->Open()); |
| 328 bytes_per_packet = aisw.channels() * aisw.samples_per_packet() * | 330 bytes_per_packet = aisw.channels() * aisw.samples_per_packet() * |
| 329 (aisw.bits_per_sample() / 8); | 331 (aisw.bits_per_sample() / 8); |
| 330 | 332 |
| 331 EXPECT_CALL(sink, OnData( | 333 EXPECT_CALL(sink, OnData( |
| 332 ais, NotNull(), bytes_per_packet, Gt(bytes_per_packet))) | 334 ais, NotNull(), bytes_per_packet, Gt(bytes_per_packet), _)) |
| 333 .Times(AtLeast(10)) | 335 .Times(AtLeast(10)) |
| 334 .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop)); | 336 .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop)); |
| 335 ais->Start(&sink); | 337 ais->Start(&sink); |
| 336 loop.Run(); | 338 loop.Run(); |
| 337 ais->Stop(); | 339 ais->Stop(); |
| 338 | 340 |
| 339 EXPECT_CALL(sink, OnClose(ais)) | 341 EXPECT_CALL(sink, OnClose(ais)) |
| 340 .Times(1); | 342 .Times(1); |
| 341 ais->Close(); | 343 ais->Close(); |
| 342 | 344 |
| 343 // 5 ms packet size. | 345 // 5 ms packet size. |
| 344 | 346 |
| 345 count = 0; | 347 count = 0; |
| 346 ais = aisw.Create(samples_per_packet_10ms / 2); | 348 ais = aisw.Create(samples_per_packet_10ms / 2); |
| 347 EXPECT_TRUE(ais->Open()); | 349 EXPECT_TRUE(ais->Open()); |
| 348 bytes_per_packet = aisw.channels() * aisw.samples_per_packet() * | 350 bytes_per_packet = aisw.channels() * aisw.samples_per_packet() * |
| 349 (aisw.bits_per_sample() / 8); | 351 (aisw.bits_per_sample() / 8); |
| 350 | 352 |
| 351 EXPECT_CALL(sink, OnData( | 353 EXPECT_CALL(sink, OnData( |
| 352 ais, NotNull(), bytes_per_packet, Gt(bytes_per_packet))) | 354 ais, NotNull(), bytes_per_packet, Gt(bytes_per_packet), _)) |
| 353 .Times(AtLeast(10)) | 355 .Times(AtLeast(10)) |
| 354 .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop)); | 356 .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop)); |
| 355 ais->Start(&sink); | 357 ais->Start(&sink); |
| 356 loop.Run(); | 358 loop.Run(); |
| 357 ais->Stop(); | 359 ais->Stop(); |
| 358 | 360 |
| 359 EXPECT_CALL(sink, OnClose(ais)) | 361 EXPECT_CALL(sink, OnClose(ais)) |
| 360 .Times(1); | 362 .Times(1); |
| 361 ais->Close(); | 363 ais->Close(); |
| 362 } | 364 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 383 | 385 |
| 384 LOG(INFO) << ">> Sample rate: " << aisw.sample_rate() << " [Hz]"; | 386 LOG(INFO) << ">> Sample rate: " << aisw.sample_rate() << " [Hz]"; |
| 385 WriteToFileAudioSink file_sink(file_name); | 387 WriteToFileAudioSink file_sink(file_name); |
| 386 LOG(INFO) << ">> Speak into the default microphone while recording."; | 388 LOG(INFO) << ">> Speak into the default microphone while recording."; |
| 387 ais->Start(&file_sink); | 389 ais->Start(&file_sink); |
| 388 base::PlatformThread::Sleep(TestTimeouts::action_timeout_ms()); | 390 base::PlatformThread::Sleep(TestTimeouts::action_timeout_ms()); |
| 389 ais->Stop(); | 391 ais->Stop(); |
| 390 LOG(INFO) << ">> Recording has stopped."; | 392 LOG(INFO) << ">> Recording has stopped."; |
| 391 ais->Close(); | 393 ais->Close(); |
| 392 } | 394 } |
| OLD | NEW |