Index: media/audio/win/audio_unified_win_unittest.cc |
diff --git a/media/audio/win/audio_unified_win_unittest.cc b/media/audio/win/audio_unified_win_unittest.cc |
deleted file mode 100644 |
index fadec6188c35052e26935a93847a788c82b013f8..0000000000000000000000000000000000000000 |
--- a/media/audio/win/audio_unified_win_unittest.cc |
+++ /dev/null |
@@ -1,356 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "base/basictypes.h" |
-#include "base/command_line.h" |
-#include "base/file_util.h" |
-#include "base/message_loop/message_loop.h" |
-#include "base/path_service.h" |
-#include "base/test/test_timeouts.h" |
-#include "base/time/time.h" |
-#include "base/win/scoped_com_initializer.h" |
-#include "media/audio/audio_io.h" |
-#include "media/audio/audio_manager.h" |
-#include "media/audio/mock_audio_source_callback.h" |
-#include "media/audio/win/audio_unified_win.h" |
-#include "media/audio/win/core_audio_util_win.h" |
-#include "media/base/channel_mixer.h" |
-#include "media/base/media_switches.h" |
-#include "testing/gmock/include/gmock/gmock.h" |
-#include "testing/gtest/include/gtest/gtest.h" |
- |
-using ::testing::_; |
-using ::testing::AtLeast; |
-using ::testing::Between; |
-using ::testing::DoAll; |
-using ::testing::NotNull; |
-using ::testing::Return; |
-using base::win::ScopedCOMInitializer; |
- |
-namespace media { |
- |
-static const size_t kMaxDeltaSamples = 1000; |
-static const char kDeltaTimeMsFileName[] = "unified_delta_times_ms.txt"; |
- |
-// Verify that the delay estimate in the OnMoreIOData() callback is larger |
-// than an expected minumum value. |
-MATCHER_P(DelayGreaterThan, value, "") { |
- return (arg.hardware_delay_bytes > value.hardware_delay_bytes); |
-} |
- |
-// Used to terminate a loop from a different thread than the loop belongs to. |
-// |loop| should be a MessageLoopProxy. |
-ACTION_P(QuitLoop, loop) { |
- loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); |
-} |
- |
-// AudioOutputStream::AudioSourceCallback implementation which enables audio |
-// play-through. It also creates a text file that contains times between two |
-// successive callbacks. Units are in milliseconds. This file can be used for |
-// off-line analysis of the callback sequence. |
-class UnifiedSourceCallback : public AudioOutputStream::AudioSourceCallback { |
- public: |
- explicit UnifiedSourceCallback() |
- : previous_call_time_(base::TimeTicks::Now()), |
- text_file_(NULL), |
- elements_to_write_(0) { |
- delta_times_.reset(new int[kMaxDeltaSamples]); |
- } |
- |
- virtual ~UnifiedSourceCallback() { |
- base::FilePath file_name; |
- EXPECT_TRUE(PathService::Get(base::DIR_EXE, &file_name)); |
- file_name = file_name.AppendASCII(kDeltaTimeMsFileName); |
- |
- EXPECT_TRUE(!text_file_); |
- text_file_ = base::OpenFile(file_name, "wt"); |
- DLOG_IF(ERROR, !text_file_) << "Failed to open log file."; |
- VLOG(0) << ">> Output file " << file_name.value() << " has been created."; |
- |
- // Write the array which contains delta times to a text file. |
- size_t elements_written = 0; |
- while (elements_written < elements_to_write_) { |
- fprintf(text_file_, "%d\n", delta_times_[elements_written]); |
- ++elements_written; |
- } |
- base::CloseFile(text_file_); |
- } |
- |
- virtual int OnMoreData(AudioBus* dest, |
- AudioBuffersState buffers_state) { |
- NOTREACHED(); |
- return 0; |
- }; |
- |
- virtual int OnMoreIOData(AudioBus* source, |
- AudioBus* dest, |
- AudioBuffersState buffers_state) { |
- // Store time between this callback and the previous callback. |
- const base::TimeTicks now_time = base::TimeTicks::Now(); |
- const int diff = (now_time - previous_call_time_).InMilliseconds(); |
- previous_call_time_ = now_time; |
- if (elements_to_write_ < kMaxDeltaSamples) { |
- delta_times_[elements_to_write_] = diff; |
- ++elements_to_write_; |
- } |
- |
- // Play out the recorded audio samples in loop back. Perform channel mixing |
- // if required using a channel mixer which is created only if needed. |
- if (source->channels() == dest->channels()) { |
- source->CopyTo(dest); |
- } else { |
- // A channel mixer is required for converting audio between two different |
- // channel layouts. |
- if (!channel_mixer_) { |
- // Guessing the channel layout will work OK for this unit test. |
- // Main thing is that the number of channels is correct. |
- ChannelLayout input_layout = GuessChannelLayout(source->channels()); |
- ChannelLayout output_layout = GuessChannelLayout(dest->channels()); |
- channel_mixer_.reset(new ChannelMixer(input_layout, output_layout)); |
- DVLOG(1) << "Remixing channel layout from " << input_layout |
- << " to " << output_layout << "; from " |
- << source->channels() << " channels to " |
- << dest->channels() << " channels."; |
- } |
- if (channel_mixer_) |
- channel_mixer_->Transform(source, dest); |
- } |
- return source->frames(); |
- }; |
- |
- virtual void OnError(AudioOutputStream* stream) { |
- NOTREACHED(); |
- } |
- |
- private: |
- base::TimeTicks previous_call_time_; |
- scoped_ptr<int[]> delta_times_; |
- FILE* text_file_; |
- size_t elements_to_write_; |
- scoped_ptr<ChannelMixer> channel_mixer_; |
-}; |
- |
-// Convenience method which ensures that we fulfill all required conditions |
-// to run unified audio tests on Windows. |
-static bool CanRunUnifiedAudioTests(AudioManager* audio_man) { |
- if (!CoreAudioUtil::IsSupported()) { |
- LOG(WARNING) << "This tests requires Windows Vista or higher."; |
- return false; |
- } |
- |
- if (!audio_man->HasAudioOutputDevices()) { |
- LOG(WARNING) << "No output devices detected."; |
- return false; |
- } |
- |
- if (!audio_man->HasAudioInputDevices()) { |
- LOG(WARNING) << "No input devices detected."; |
- return false; |
- } |
- |
- return true; |
-} |
- |
-// Convenience class which simplifies creation of a unified AudioOutputStream |
-// object. |
-class AudioUnifiedStreamWrapper { |
- public: |
- explicit AudioUnifiedStreamWrapper(AudioManager* audio_manager) |
- : com_init_(ScopedCOMInitializer::kMTA), |
- audio_man_(audio_manager) { |
- // We open up both both sides (input and output) using the preferred |
- // set of audio parameters. These parameters corresponds to the mix format |
- // that the audio engine uses internally for processing of shared-mode |
- // output streams. |
- AudioParameters out_params; |
- EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters( |
- eRender, eConsole, &out_params))); |
- |
- // WebAudio is the only real user of unified audio and it always asks |
- // for stereo. |
- // TODO(henrika): extend support to other input channel layouts as well. |
- const int kInputChannels = 2; |
- |
- params_.Reset(out_params.format(), |
- out_params.channel_layout(), |
- out_params.channels(), |
- kInputChannels, |
- out_params.sample_rate(), |
- out_params.bits_per_sample(), |
- out_params.frames_per_buffer()); |
- } |
- |
- ~AudioUnifiedStreamWrapper() {} |
- |
- // Creates an AudioOutputStream object using default parameters. |
- WASAPIUnifiedStream* Create() { |
- return static_cast<WASAPIUnifiedStream*>(CreateOutputStream()); |
- } |
- |
- // Creates an AudioOutputStream object using default parameters but a |
- // specified input device. |
- WASAPIUnifiedStream* Create(const std::string device_id) { |
- return static_cast<WASAPIUnifiedStream*>(CreateOutputStream(device_id)); |
- } |
- |
- AudioParameters::Format format() const { return params_.format(); } |
- int channels() const { return params_.channels(); } |
- int bits_per_sample() const { return params_.bits_per_sample(); } |
- int sample_rate() const { return params_.sample_rate(); } |
- int frames_per_buffer() const { return params_.frames_per_buffer(); } |
- int bytes_per_buffer() const { return params_.GetBytesPerBuffer(); } |
- int input_channels() const { return params_.input_channels(); } |
- |
- private: |
- AudioOutputStream* CreateOutputStream() { |
- // Get the unique device ID of the default capture device instead of using |
- // AudioManagerBase::kDefaultDeviceId since it provides slightly better |
- // test coverage and will utilize the same code path as if a non default |
- // input device was used. |
- ScopedComPtr<IMMDevice> audio_device = |
- CoreAudioUtil::CreateDefaultDevice(eCapture, eConsole); |
- AudioDeviceName name; |
- EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDeviceName(audio_device, &name))); |
- const std::string& input_device_id = name.unique_id; |
- EXPECT_TRUE(CoreAudioUtil::DeviceIsDefault(eCapture, eConsole, |
- input_device_id)); |
- |
- // Create the unified audio I/O stream using the default input device. |
- AudioOutputStream* aos = audio_man_->MakeAudioOutputStream(params_, |
- "", input_device_id); |
- EXPECT_TRUE(aos); |
- return aos; |
- } |
- |
- AudioOutputStream* CreateOutputStream(const std::string& input_device_id) { |
- // Create the unified audio I/O stream using the specified input device. |
- AudioOutputStream* aos = audio_man_->MakeAudioOutputStream(params_, |
- "", input_device_id); |
- EXPECT_TRUE(aos); |
- return aos; |
- } |
- |
- ScopedCOMInitializer com_init_; |
- AudioManager* audio_man_; |
- AudioParameters params_; |
-}; |
- |
-// Convenience method which creates a default WASAPIUnifiedStream object. |
-static WASAPIUnifiedStream* CreateDefaultUnifiedStream( |
- AudioManager* audio_manager) { |
- AudioUnifiedStreamWrapper aosw(audio_manager); |
- return aosw.Create(); |
-} |
- |
-// Convenience method which creates a default WASAPIUnifiedStream object but |
-// with a specified audio input device. |
-static WASAPIUnifiedStream* CreateDefaultUnifiedStream( |
- AudioManager* audio_manager, const std::string& device_id) { |
- AudioUnifiedStreamWrapper aosw(audio_manager); |
- return aosw.Create(device_id); |
-} |
- |
-// Test Open(), Close() calling sequence. |
-TEST(WASAPIUnifiedStreamTest, OpenAndClose) { |
- scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); |
- if (!CanRunUnifiedAudioTests(audio_manager.get())) |
- return; |
- |
- WASAPIUnifiedStream* wus = CreateDefaultUnifiedStream(audio_manager.get()); |
- EXPECT_TRUE(wus->Open()); |
- wus->Close(); |
-} |
- |
-// Test Open(), Close() calling sequence for all available capture devices. |
-TEST(WASAPIUnifiedStreamTest, OpenAndCloseForAllInputDevices) { |
- scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); |
- if (!CanRunUnifiedAudioTests(audio_manager.get())) |
- return; |
- |
- AudioDeviceNames device_names; |
- audio_manager->GetAudioInputDeviceNames(&device_names); |
- for (AudioDeviceNames::iterator i = device_names.begin(); |
- i != device_names.end(); ++i) { |
- WASAPIUnifiedStream* wus = CreateDefaultUnifiedStream( |
- audio_manager.get(), i->unique_id); |
- EXPECT_TRUE(wus->Open()); |
- wus->Close(); |
- } |
-} |
- |
-// Test Open(), Start(), Close() calling sequence. |
-TEST(WASAPIUnifiedStreamTest, OpenStartAndClose) { |
- scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); |
- if (!CanRunUnifiedAudioTests(audio_manager.get())) |
- return; |
- |
- MockAudioSourceCallback source; |
- AudioUnifiedStreamWrapper ausw(audio_manager.get()); |
- WASAPIUnifiedStream* wus = ausw.Create(); |
- |
- EXPECT_TRUE(wus->Open()); |
- EXPECT_CALL(source, OnError(wus)) |
- .Times(0); |
- EXPECT_CALL(source, OnMoreIOData(NotNull(), NotNull(), _)) |
- .Times(Between(0, 1)) |
- .WillOnce(Return(ausw.frames_per_buffer())); |
- wus->Start(&source); |
- wus->Close(); |
-} |
- |
-// Verify that IO callbacks starts as they should. |
-TEST(WASAPIUnifiedStreamTest, StartLoopbackAudio) { |
- scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); |
- if (!CanRunUnifiedAudioTests(audio_manager.get())) |
- return; |
- |
- base::MessageLoopForUI loop; |
- MockAudioSourceCallback source; |
- AudioUnifiedStreamWrapper ausw(audio_manager.get()); |
- WASAPIUnifiedStream* wus = ausw.Create(); |
- |
- // Set up expected minimum delay estimation where we use a minium delay |
- // which is equal to the sum of render and capture sizes. We can never |
- // reach a delay lower than this value. |
- AudioBuffersState min_total_audio_delay(0, 2 * ausw.bytes_per_buffer()); |
- |
- EXPECT_TRUE(wus->Open()); |
- EXPECT_CALL(source, OnError(wus)) |
- .Times(0); |
- EXPECT_CALL(source, OnMoreIOData( |
- NotNull(), NotNull(), DelayGreaterThan(min_total_audio_delay))) |
- .Times(AtLeast(2)) |
- .WillOnce(Return(ausw.frames_per_buffer())) |
- .WillOnce(DoAll( |
- QuitLoop(loop.message_loop_proxy()), |
- Return(ausw.frames_per_buffer()))); |
- wus->Start(&source); |
- loop.PostDelayedTask(FROM_HERE, base::MessageLoop::QuitClosure(), |
- TestTimeouts::action_timeout()); |
- loop.Run(); |
- wus->Stop(); |
- wus->Close(); |
-} |
- |
-// Perform a real-time test in loopback where the recorded audio is echoed |
-// back to the speaker. This test allows the user to verify that the audio |
-// sounds OK. A text file with name |kDeltaTimeMsFileName| is also generated. |
-TEST(WASAPIUnifiedStreamTest, DISABLED_RealTimePlayThrough) { |
- scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); |
- if (!CanRunUnifiedAudioTests(audio_manager.get())) |
- return; |
- |
- base::MessageLoopForUI loop; |
- UnifiedSourceCallback source; |
- WASAPIUnifiedStream* wus = CreateDefaultUnifiedStream(audio_manager.get()); |
- |
- EXPECT_TRUE(wus->Open()); |
- wus->Start(&source); |
- loop.PostDelayedTask(FROM_HERE, base::MessageLoop::QuitClosure(), |
- base::TimeDelta::FromMilliseconds(10000)); |
- loop.Run(); |
- wus->Close(); |
-} |
- |
-} // namespace media |