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 "media/audio/win/audio_low_latency_input_win.h" | 5 #include "media/audio/win/audio_low_latency_input_win.h" |
6 | 6 |
7 #include <windows.h> | |
8 #include <mmsystem.h> | 7 #include <mmsystem.h> |
9 #include <stddef.h> | 8 #include <stddef.h> |
10 #include <stdint.h> | 9 #include <stdint.h> |
| 10 #include <windows.h> |
11 | 11 |
12 #include <memory> | 12 #include <memory> |
13 | 13 |
14 #include "base/environment.h" | 14 #include "base/environment.h" |
15 #include "base/files/file_util.h" | 15 #include "base/files/file_util.h" |
16 #include "base/macros.h" | 16 #include "base/macros.h" |
17 #include "base/message_loop/message_loop.h" | 17 #include "base/message_loop/message_loop.h" |
18 #include "base/path_service.h" | 18 #include "base/path_service.h" |
19 #include "base/run_loop.h" | 19 #include "base/run_loop.h" |
20 #include "base/single_thread_task_runner.h" | 20 #include "base/single_thread_task_runner.h" |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
57 FakeAudioInputCallback() | 57 FakeAudioInputCallback() |
58 : num_received_audio_frames_(0), | 58 : num_received_audio_frames_(0), |
59 data_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC, | 59 data_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC, |
60 base::WaitableEvent::InitialState::NOT_SIGNALED), | 60 base::WaitableEvent::InitialState::NOT_SIGNALED), |
61 error_(false) {} | 61 error_(false) {} |
62 | 62 |
63 bool error() const { return error_; } | 63 bool error() const { return error_; } |
64 int num_received_audio_frames() const { return num_received_audio_frames_; } | 64 int num_received_audio_frames() const { return num_received_audio_frames_; } |
65 | 65 |
66 // Waits until OnData() is called on another thread. | 66 // Waits until OnData() is called on another thread. |
67 void WaitForData() { | 67 void WaitForData() { data_event_.Wait(); } |
68 data_event_.Wait(); | |
69 } | |
70 | 68 |
71 void OnData(AudioInputStream* stream, | 69 void OnData(AudioInputStream* stream, |
72 const AudioBus* src, | 70 const AudioBus* src, |
73 uint32_t hardware_delay_bytes, | 71 uint32_t hardware_delay_bytes, |
74 double volume) override { | 72 double volume) override { |
75 EXPECT_GE(hardware_delay_bytes, 0u); | 73 EXPECT_GE(hardware_delay_bytes, 0u); |
76 EXPECT_LT(hardware_delay_bytes, 0xFFFFu); // Arbitrarily picked. | 74 EXPECT_LT(hardware_delay_bytes, 0xFFFFu); // Arbitrarily picked. |
77 num_received_audio_frames_ += src->frames(); | 75 num_received_audio_frames_ += src->frames(); |
78 data_event_.Signal(); | 76 data_event_.Signal(); |
79 } | 77 } |
80 | 78 |
81 void OnError(AudioInputStream* stream) override { | 79 void OnError(AudioInputStream* stream) override { error_ = true; } |
82 error_ = true; | |
83 } | |
84 | 80 |
85 private: | 81 private: |
86 int num_received_audio_frames_; | 82 int num_received_audio_frames_; |
87 base::WaitableEvent data_event_; | 83 base::WaitableEvent data_event_; |
88 bool error_; | 84 bool error_; |
89 | 85 |
90 DISALLOW_COPY_AND_ASSIGN(FakeAudioInputCallback); | 86 DISALLOW_COPY_AND_ASSIGN(FakeAudioInputCallback); |
91 }; | 87 }; |
92 | 88 |
93 // This audio sink implementation should be used for manual tests only since | 89 // This audio sink implementation should be used for manual tests only since |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
170 class AudioInputStreamWrapper { | 166 class AudioInputStreamWrapper { |
171 public: | 167 public: |
172 explicit AudioInputStreamWrapper(AudioManager* audio_manager) | 168 explicit AudioInputStreamWrapper(AudioManager* audio_manager) |
173 : audio_man_(audio_manager) { | 169 : audio_man_(audio_manager) { |
174 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters( | 170 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters( |
175 AudioDeviceDescription::kDefaultDeviceId, false, &default_params_))); | 171 AudioDeviceDescription::kDefaultDeviceId, false, &default_params_))); |
176 EXPECT_EQ(format(), AudioParameters::AUDIO_PCM_LOW_LATENCY); | 172 EXPECT_EQ(format(), AudioParameters::AUDIO_PCM_LOW_LATENCY); |
177 frames_per_buffer_ = default_params_.frames_per_buffer(); | 173 frames_per_buffer_ = default_params_.frames_per_buffer(); |
178 } | 174 } |
179 | 175 |
| 176 AudioInputStreamWrapper(AudioManager* audio_manager, |
| 177 const AudioParameters& default_params) |
| 178 : audio_man_(audio_manager), default_params_(default_params) { |
| 179 EXPECT_EQ(format(), AudioParameters::AUDIO_PCM_LOW_LATENCY); |
| 180 frames_per_buffer_ = default_params_.frames_per_buffer(); |
| 181 } |
| 182 |
180 ~AudioInputStreamWrapper() {} | 183 ~AudioInputStreamWrapper() {} |
181 | 184 |
182 // Creates AudioInputStream object using default parameters. | 185 // Creates AudioInputStream object using default parameters. |
183 AudioInputStream* Create() { | 186 AudioInputStream* Create() { return CreateInputStream(); } |
184 return CreateInputStream(); | |
185 } | |
186 | 187 |
187 // Creates AudioInputStream object using non-default parameters where the | 188 // Creates AudioInputStream object using non-default parameters where the |
188 // frame size is modified. | 189 // frame size is modified. |
189 AudioInputStream* Create(int frames_per_buffer) { | 190 AudioInputStream* Create(int frames_per_buffer) { |
190 frames_per_buffer_ = frames_per_buffer; | 191 frames_per_buffer_ = frames_per_buffer; |
191 return CreateInputStream(); | 192 return CreateInputStream(); |
192 } | 193 } |
193 | 194 |
194 AudioParameters::Format format() const { return default_params_.format(); } | 195 AudioParameters::Format format() const { return default_params_.format(); } |
195 int channels() const { | 196 int channels() const { |
(...skipping 22 matching lines...) Expand all Loading... |
218 // Convenience method which creates a default AudioInputStream object. | 219 // Convenience method which creates a default AudioInputStream object. |
219 static AudioInputStream* CreateDefaultAudioInputStream( | 220 static AudioInputStream* CreateDefaultAudioInputStream( |
220 AudioManager* audio_manager) { | 221 AudioManager* audio_manager) { |
221 AudioInputStreamWrapper aisw(audio_manager); | 222 AudioInputStreamWrapper aisw(audio_manager); |
222 AudioInputStream* ais = aisw.Create(); | 223 AudioInputStream* ais = aisw.Create(); |
223 return ais; | 224 return ais; |
224 } | 225 } |
225 | 226 |
226 class ScopedAudioInputStream { | 227 class ScopedAudioInputStream { |
227 public: | 228 public: |
228 explicit ScopedAudioInputStream(AudioInputStream* stream) | 229 explicit ScopedAudioInputStream(AudioInputStream* stream) : stream_(stream) {} |
229 : stream_(stream) {} | |
230 | 230 |
231 ~ScopedAudioInputStream() { | 231 ~ScopedAudioInputStream() { |
232 if (stream_) | 232 if (stream_) |
233 stream_->Close(); | 233 stream_->Close(); |
234 } | 234 } |
235 | 235 |
236 void Close() { | 236 void Close() { |
237 if (stream_) | 237 if (stream_) |
238 stream_->Close(); | 238 stream_->Close(); |
239 stream_ = NULL; | 239 stream_ = NULL; |
240 } | 240 } |
241 | 241 |
242 AudioInputStream* operator->() { | 242 AudioInputStream* operator->() { return stream_; } |
243 return stream_; | |
244 } | |
245 | 243 |
246 AudioInputStream* get() const { return stream_; } | 244 AudioInputStream* get() const { return stream_; } |
247 | 245 |
248 void Reset(AudioInputStream* new_stream) { | 246 void Reset(AudioInputStream* new_stream) { |
249 Close(); | 247 Close(); |
250 stream_ = new_stream; | 248 stream_ = new_stream; |
251 } | 249 } |
252 | 250 |
253 private: | 251 private: |
254 AudioInputStream* stream_; | 252 AudioInputStream* stream_; |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
397 // Store current packet size (to be used in the subsequent tests). | 395 // Store current packet size (to be used in the subsequent tests). |
398 int frames_per_buffer_10ms = aisw.frames_per_buffer(); | 396 int frames_per_buffer_10ms = aisw.frames_per_buffer(); |
399 | 397 |
400 ais.Close(); | 398 ais.Close(); |
401 | 399 |
402 // 20 ms packet size. | 400 // 20 ms packet size. |
403 | 401 |
404 count = 0; | 402 count = 0; |
405 ais.Reset(aisw.Create(2 * frames_per_buffer_10ms)); | 403 ais.Reset(aisw.Create(2 * frames_per_buffer_10ms)); |
406 EXPECT_TRUE(ais->Open()); | 404 EXPECT_TRUE(ais->Open()); |
407 bytes_per_packet = aisw.channels() * aisw.frames_per_buffer() * | 405 bytes_per_packet = |
408 (aisw.bits_per_sample() / 8); | 406 aisw.channels() * aisw.frames_per_buffer() * (aisw.bits_per_sample() / 8); |
409 | 407 |
410 { | 408 { |
411 base::RunLoop run_loop; | 409 base::RunLoop run_loop; |
412 EXPECT_CALL(sink, OnData(ais.get(), NotNull(), _, _)) | 410 EXPECT_CALL(sink, OnData(ais.get(), NotNull(), _, _)) |
413 .Times(AtLeast(10)) | 411 .Times(AtLeast(10)) |
414 .WillRepeatedly( | 412 .WillRepeatedly( |
415 CheckCountAndPostQuitTask(&count, 10, message_loop_.task_runner(), | 413 CheckCountAndPostQuitTask(&count, 10, message_loop_.task_runner(), |
416 run_loop.QuitWhenIdleClosure())); | 414 run_loop.QuitWhenIdleClosure())); |
417 ais->Start(&sink); | 415 ais->Start(&sink); |
418 run_loop.Run(); | 416 run_loop.Run(); |
419 ais->Stop(); | 417 ais->Stop(); |
420 ais.Close(); | 418 ais.Close(); |
421 } | 419 } |
422 | 420 |
423 // 5 ms packet size. | 421 // 5 ms packet size. |
424 | 422 |
425 count = 0; | 423 count = 0; |
426 ais.Reset(aisw.Create(frames_per_buffer_10ms / 2)); | 424 ais.Reset(aisw.Create(frames_per_buffer_10ms / 2)); |
427 EXPECT_TRUE(ais->Open()); | 425 EXPECT_TRUE(ais->Open()); |
428 bytes_per_packet = aisw.channels() * aisw.frames_per_buffer() * | 426 bytes_per_packet = |
429 (aisw.bits_per_sample() / 8); | 427 aisw.channels() * aisw.frames_per_buffer() * (aisw.bits_per_sample() / 8); |
430 | 428 |
431 { | 429 { |
432 base::RunLoop run_loop; | 430 base::RunLoop run_loop; |
433 EXPECT_CALL(sink, OnData(ais.get(), NotNull(), _, _)) | 431 EXPECT_CALL(sink, OnData(ais.get(), NotNull(), _, _)) |
434 .Times(AtLeast(10)) | 432 .Times(AtLeast(10)) |
435 .WillRepeatedly( | 433 .WillRepeatedly( |
436 CheckCountAndPostQuitTask(&count, 10, message_loop_.task_runner(), | 434 CheckCountAndPostQuitTask(&count, 10, message_loop_.task_runner(), |
437 run_loop.QuitWhenIdleClosure())); | 435 run_loop.QuitWhenIdleClosure())); |
438 ais->Start(&sink); | 436 ais->Start(&sink); |
439 run_loop.Run(); | 437 run_loop.Run(); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
476 // By default, GTest will print out YOU HAVE 1 DISABLED TEST. | 474 // By default, GTest will print out YOU HAVE 1 DISABLED TEST. |
477 // To include disabled tests in test execution, just invoke the test program | 475 // To include disabled tests in test execution, just invoke the test program |
478 // with --gtest_also_run_disabled_tests or set the GTEST_ALSO_RUN_DISABLED_TESTS | 476 // with --gtest_also_run_disabled_tests or set the GTEST_ALSO_RUN_DISABLED_TESTS |
479 // environment variable to a value greater than 0. | 477 // environment variable to a value greater than 0. |
480 TEST_F(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamRecordToFile) { | 478 TEST_F(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamRecordToFile) { |
481 ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); | 479 ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); |
482 | 480 |
483 // Name of the output PCM file containing captured data. The output file | 481 // Name of the output PCM file containing captured data. The output file |
484 // will be stored in the directory containing 'media_unittests.exe'. | 482 // will be stored in the directory containing 'media_unittests.exe'. |
485 // Example of full name: \src\build\Debug\out_stereo_10sec.pcm. | 483 // Example of full name: \src\build\Debug\out_stereo_10sec.pcm. |
486 const char* file_name = "out_stereo_10sec.pcm"; | 484 const char* file_name = "out_10sec.pcm"; |
487 | 485 |
488 AudioInputStreamWrapper aisw(audio_manager_.get()); | 486 AudioInputStreamWrapper aisw(audio_manager_.get()); |
489 ScopedAudioInputStream ais(aisw.Create()); | 487 ScopedAudioInputStream ais(aisw.Create()); |
490 EXPECT_TRUE(ais->Open()); | 488 ASSERT_TRUE(ais->Open()); |
491 | 489 |
492 VLOG(0) << ">> Sample rate: " << aisw.sample_rate() << " [Hz]"; | 490 VLOG(0) << ">> Sample rate: " << aisw.sample_rate() << " [Hz]"; |
493 WriteToFileAudioSink file_sink(file_name, aisw.bits_per_sample()); | 491 WriteToFileAudioSink file_sink(file_name, aisw.bits_per_sample()); |
494 VLOG(0) << ">> Speak into the default microphone while recording."; | 492 VLOG(0) << ">> Speak into the default microphone while recording."; |
495 ais->Start(&file_sink); | 493 ais->Start(&file_sink); |
496 base::PlatformThread::Sleep(TestTimeouts::action_timeout()); | 494 base::PlatformThread::Sleep(TestTimeouts::action_timeout()); |
497 ais->Stop(); | 495 ais->Stop(); |
498 VLOG(0) << ">> Recording has stopped."; | 496 VLOG(0) << ">> Recording has stopped."; |
499 ais.Close(); | 497 ais.Close(); |
500 } | 498 } |
501 | 499 |
| 500 TEST_F(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamResampleToFile) { |
| 501 ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); |
| 502 |
| 503 // This is basically the same test as WASAPIAudioInputStreamRecordToFile |
| 504 // except it forces use of a different sample rate than is preferred by |
| 505 // the hardware. This functionality is offered while we still have code |
| 506 // that doesn't ask the lower levels for what the preferred audio parameters |
| 507 // are (and previously depended on the old Wave API to do this automatically). |
| 508 |
| 509 AudioParameters params; |
| 510 ASSERT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters( |
| 511 AudioDeviceDescription::kDefaultDeviceId, false, ¶ms))); |
| 512 |
| 513 VLOG(0) << ">> Hardware sample rate: " << params.sample_rate() << " [Hz]"; |
| 514 |
| 515 params.set_sample_rate(params.sample_rate() == 48000 ? 44100 : 48000); |
| 516 params.set_frames_per_buffer(params.sample_rate() / 100); |
| 517 |
| 518 static const char kFileName[] = "out_10sec_resampled.pcm"; |
| 519 |
| 520 AudioInputStreamWrapper aisw(audio_manager_.get(), params); |
| 521 ScopedAudioInputStream ais(aisw.Create()); |
| 522 ASSERT_TRUE(ais->Open()); |
| 523 |
| 524 VLOG(0) << ">> Resampled rate will be: " << aisw.sample_rate() << " [Hz]"; |
| 525 WriteToFileAudioSink file_sink(kFileName, aisw.bits_per_sample()); |
| 526 VLOG(0) << ">> Speak into the default microphone while recording."; |
| 527 ais->Start(&file_sink); |
| 528 base::PlatformThread::Sleep(TestTimeouts::action_timeout()); |
| 529 ais->Stop(); |
| 530 VLOG(0) << ">> Recording has stopped."; |
| 531 ais.Close(); |
| 532 } |
| 533 |
502 } // namespace media | 534 } // namespace media |
OLD | NEW |