// 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 #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "media/audio/audio_io.h" #include "media/audio/audio_manager_base.h" #include "media/audio/audio_unittest_util.h" #include "testing/gtest/include/gtest/gtest.h" #if defined(OS_WIN) #include "base/win/scoped_com_initializer.h" #include "media/audio/win/core_audio_util_win.h" #endif namespace media { double GetVolumeAfterSetVolumeOnLinux(AudioInputStream* ais, double target_volume) { // SetVolume() is asynchronous on Linux, we need to keep trying until // the SetVolume() operation is done. static const int kTimesToRun = 10; double volume = 0.0; for (int i = 0; i < kTimesToRun; ++i) { volume = ais->GetVolume(); if (volume == target_volume) break; // Sleep 100ms to wait for the operation. base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); } return volume; } class AudioInputVolumeTest : public ::testing::Test { protected: AudioInputVolumeTest() : audio_manager_(AudioManager::CreateForTesting()) #if defined(OS_WIN) , com_init_(base::win::ScopedCOMInitializer::kMTA) #endif { } bool HasCoreAudioAndInputDevices() { #if defined(OS_WIN) // TODO(henrika): add support for volume control on Windows XP as well. if (!CoreAudioUtil::IsSupported()) return false; #endif return audio_manager_->HasAudioInputDevices(); } // Helper method which checks if the stream has volume support. bool HasDeviceVolumeControl(AudioInputStream* stream) { if (!stream) return false; return (stream->GetMaxVolume() != 0.0); } AudioInputStream* CreateAndOpenStream(const std::string& device_id) { const AudioParameters& params = audio_manager_->GetInputStreamParameters(device_id); AudioInputStream* ais = audio_manager_->MakeAudioInputStream( params, device_id); EXPECT_TRUE(NULL != ais); #if defined(OS_LINUX) || defined(OS_OPENBSD) // Some linux devices do not support our settings, we may fail to open // those devices. if (!ais->Open()) { // Default device should always be able to be opened. EXPECT_TRUE(AudioManagerBase::kDefaultDeviceId != device_id); ais->Close(); ais = NULL; } #elif defined(OS_WIN) || defined(OS_MACOSX) EXPECT_TRUE(ais->Open()); #endif return ais; } scoped_ptr audio_manager_; #if defined(OS_WIN) base::win::ScopedCOMInitializer com_init_; #endif }; #if defined(OS_LINUX) && !defined(OS_CHROMEOS) // Currently failing on linux ARM bot: http://crbug/238490 // Also flaky on x86_64: http://crbug/236936 #define MAYBE_InputVolumeTest DISABLED_InputVolumeTest #else #define MAYBE_InputVolumeTest InputVolumeTest #endif TEST_F(AudioInputVolumeTest, MAYBE_InputVolumeTest) { ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices()); // Retrieve a list of all available input devices. AudioDeviceNames device_names; audio_manager_->GetAudioInputDeviceNames(&device_names); if (device_names.empty()) { LOG(WARNING) << "Could not find any available input device"; return; } // Scan all available input devices and repeat the same test for all of them. for (AudioDeviceNames::const_iterator it = device_names.begin(); it != device_names.end(); ++it) { AudioInputStream* ais = CreateAndOpenStream(it->unique_id); if (!ais) { DLOG(WARNING) << "Failed to open stream for device " << it->unique_id; continue; } if (!HasDeviceVolumeControl(ais)) { DLOG(WARNING) << "Device: " << it->unique_id << ", does not have volume control."; ais->Close(); continue; } double max_volume = ais->GetMaxVolume(); EXPECT_GT(max_volume, 0.0); // Store the current input-device volume level. double original_volume = ais->GetVolume(); EXPECT_GE(original_volume, 0.0); #if defined(OS_WIN) || defined(OS_MACOSX) // Note that |original_volume| can be higher than |max_volume| on Linux. EXPECT_LE(original_volume, max_volume); #endif // Set the volume to the maxiumum level.. ais->SetVolume(max_volume); double current_volume = ais->GetVolume(); EXPECT_EQ(max_volume, current_volume); // Set the volume to the minimum level (=0). double new_volume = 0.0; ais->SetVolume(new_volume); #if defined(OS_LINUX) current_volume = GetVolumeAfterSetVolumeOnLinux(ais, new_volume); #else current_volume = ais->GetVolume(); #endif EXPECT_EQ(new_volume, current_volume); // Set the volume to the mid level (50% of max). // Verify that the absolute error is small enough. new_volume = max_volume / 2; ais->SetVolume(new_volume); #if defined(OS_LINUX) current_volume = GetVolumeAfterSetVolumeOnLinux(ais, new_volume); #else current_volume = ais->GetVolume(); #endif EXPECT_LT(current_volume, max_volume); EXPECT_GT(current_volume, 0); EXPECT_NEAR(current_volume, new_volume, 0.25 * max_volume); // Restores the volume to the original value. ais->SetVolume(original_volume); current_volume = ais->GetVolume(); EXPECT_EQ(original_volume, current_volume); ais->Close(); } } } // namespace media