Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(84)

Side by Side Diff: media/audio/win/audio_low_latency_input_win_unittest.cc

Issue 2690793002: Add basic resample support to WASAPIAudioInputStream. (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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, &params)));
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698