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