audio_input_volume_unittest.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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
3// found in the LICENSE file.
4
5#include <cmath>
6
7#include "base/logging.h"
8#include "base/memory/scoped_ptr.h"
9#include "media/audio/audio_io.h"
10#include "media/audio/audio_manager_base.h"
11#include "testing/gtest/include/gtest/gtest.h"
12
13#if defined(OS_WIN)
14#include "base/win/scoped_com_initializer.h"
15#include "media/audio/win/core_audio_util_win.h"
16#endif
17
18namespace media {
19
20double GetVolumeAfterSetVolumeOnLinux(AudioInputStream* ais,
21                                      double target_volume) {
22  // SetVolume() is asynchronous on Linux, we need to keep trying until
23  // the SetVolume() operation is done.
24  static const int kTimesToRun = 10;
25  double volume = 0.0;
26  for (int i = 0; i < kTimesToRun; ++i) {
27    volume = ais->GetVolume();
28    if (volume == target_volume)
29      break;
30
31    // Sleep 100ms to wait for the operation.
32    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
33  }
34
35  return volume;
36}
37
38class AudioInputVolumeTest : public ::testing::Test {
39 protected:
40  AudioInputVolumeTest()
41      : audio_manager_(AudioManager::Create())
42#if defined(OS_WIN)
43       , com_init_(base::win::ScopedCOMInitializer::kMTA)
44#endif
45  {
46  }
47
48  bool CanRunAudioTests() {
49#if defined(OS_WIN)
50    // TODO(henrika): add support for volume control on Windows XP as well.
51    // For now, we might as well signal false already here to avoid running
52    // these tests on Windows XP.
53    if (!CoreAudioUtil::IsSupported())
54      return false;
55#endif
56    if (!audio_manager_)
57      return false;
58
59    return audio_manager_->HasAudioInputDevices();
60  }
61
62  // Helper method which checks if the stream has volume support.
63  bool HasDeviceVolumeControl(AudioInputStream* stream) {
64    if (!stream)
65      return false;
66
67    return (stream->GetMaxVolume() != 0.0);
68  }
69
70  AudioInputStream* CreateAndOpenStream(const std::string& device_id) {
71    const AudioParameters& params =
72        audio_manager_->GetInputStreamParameters(device_id);
73    AudioInputStream* ais = audio_manager_->MakeAudioInputStream(
74        params, device_id);
75    EXPECT_TRUE(NULL != ais);
76
77#if defined(OS_LINUX) || defined(OS_OPENBSD)
78    // Some linux devices do not support our settings, we may fail to open
79    // those devices.
80    if (!ais->Open()) {
81      // Default device should always be able to be opened.
82      EXPECT_TRUE(AudioManagerBase::kDefaultDeviceId != device_id);
83      ais->Close();
84      ais = NULL;
85    }
86#elif defined(OS_WIN) || defined(OS_MACOSX)
87    EXPECT_TRUE(ais->Open());
88#endif
89
90    return ais;
91  }
92
93  scoped_ptr<AudioManager> audio_manager_;
94
95#if defined(OS_WIN)
96  base::win::ScopedCOMInitializer com_init_;
97#endif
98};
99
100#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
101// Currently failing on linux ARM bot: http://crbug/238490
102#define MAYBE_InputVolumeTest DISABLED_InputVolumeTest
103#else
104#define MAYBE_InputVolumeTest InputVolumeTest
105#endif
106
107TEST_F(AudioInputVolumeTest, MAYBE_InputVolumeTest) {
108  if (!CanRunAudioTests())
109    return;
110
111  // Retrieve a list of all available input devices.
112  AudioDeviceNames device_names;
113  audio_manager_->GetAudioInputDeviceNames(&device_names);
114  if (device_names.empty()) {
115    LOG(WARNING) << "Could not find any available input device";
116    return;
117  }
118
119  // Scan all available input devices and repeat the same test for all of them.
120  for (AudioDeviceNames::const_iterator it = device_names.begin();
121       it != device_names.end();
122       ++it) {
123    AudioInputStream* ais = CreateAndOpenStream(it->unique_id);
124    if (!ais) {
125      DLOG(WARNING) << "Failed to open stream for device " << it->unique_id;
126      continue;
127    }
128
129    if (!HasDeviceVolumeControl(ais)) {
130      DLOG(WARNING) << "Device: " << it->unique_id
131                    << ", does not have volume control.";
132      ais->Close();
133      continue;
134    }
135
136    double max_volume = ais->GetMaxVolume();
137    EXPECT_GT(max_volume, 0.0);
138
139    // Store the current input-device volume level.
140    double original_volume = ais->GetVolume();
141    EXPECT_GE(original_volume, 0.0);
142#if defined(OS_WIN) || defined(OS_MACOSX)
143    // Note that |original_volume| can be higher than |max_volume| on Linux.
144    EXPECT_LE(original_volume, max_volume);
145#endif
146
147    // Set the volume to the maxiumum level..
148    ais->SetVolume(max_volume);
149    double current_volume = ais->GetVolume();
150    EXPECT_EQ(max_volume, current_volume);
151
152    // Set the volume to the mininum level (=0).
153    double new_volume = 0.0;
154    ais->SetVolume(new_volume);
155#if defined(OS_LINUX)
156    current_volume = GetVolumeAfterSetVolumeOnLinux(ais, new_volume);
157#else
158    current_volume = ais->GetVolume();
159#endif
160    EXPECT_EQ(new_volume, current_volume);
161
162    // Set the volume to the mid level (50% of max).
163    // Verify that the absolute error is small enough.
164    new_volume = max_volume / 2;
165    ais->SetVolume(new_volume);
166#if defined(OS_LINUX)
167    current_volume = GetVolumeAfterSetVolumeOnLinux(ais, new_volume);
168#else
169    current_volume = ais->GetVolume();
170#endif
171    EXPECT_LT(current_volume, max_volume);
172    EXPECT_GT(current_volume, 0);
173    EXPECT_NEAR(current_volume, new_volume, 0.25 * max_volume);
174
175    // Restores the volume to the original value.
176    ais->SetVolume(original_volume);
177    current_volume = ais->GetVolume();
178    EXPECT_EQ(original_volume, current_volume);
179
180    ais->Close();
181  }
182}
183
184}  // namespace media
185