summaryrefslogtreecommitdiff
path: root/chromium/media/audio/audio_input_volume_unittest.cc
blob: 570c045570edef562130fa0a96e3ffecdcb62b11 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// 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 <cmath>

#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_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::Create())
#if defined(OS_WIN)
       , com_init_(base::win::ScopedCOMInitializer::kMTA)
#endif
  {
  }

  bool CanRunAudioTests() {
#if defined(OS_WIN)
    // TODO(henrika): add support for volume control on Windows XP as well.
    // For now, we might as well signal false already here to avoid running
    // these tests on Windows XP.
    if (!CoreAudioUtil::IsSupported())
      return false;
#endif
    if (!audio_manager_)
      return false;

    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<AudioManager> audio_manager_;

#if defined(OS_WIN)
  base::win::ScopedCOMInitializer com_init_;
#endif
};

#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
// Currently failing on linux ARM bot: http://crbug/238490
#define MAYBE_InputVolumeTest DISABLED_InputVolumeTest
#else
#define MAYBE_InputVolumeTest InputVolumeTest
#endif

TEST_F(AudioInputVolumeTest, MAYBE_InputVolumeTest) {
  if (!CanRunAudioTests())
    return;

  // 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 mininum 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