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 "services/audio/input_controller.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "base/macros.h"
11 #include "base/run_loop.h"
12 #include "base/test/scoped_feature_list.h"
13 #include "base/test/task_environment.h"
14 #include "media/audio/audio_manager.h"
15 #include "media/audio/fake_audio_input_stream.h"
16 #include "media/audio/fake_audio_log_factory.h"
17 #include "media/audio/fake_audio_manager.h"
18 #include "media/audio/test_audio_thread.h"
19 #include "media/base/audio_processing.h"
20 #include "media/base/user_input_monitor.h"
21 #include "media/webrtc/audio_processor.h"
22 #include "media/webrtc/webrtc_switches.h"
23 #include "mojo/public/cpp/bindings/remote.h"
24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26
27 using ::testing::_;
28 using ::testing::AtLeast;
29 using ::testing::Exactly;
30 using ::testing::InvokeWithoutArgs;
31 using ::testing::NotNull;
32 using base::WaitableEvent;
33
34 namespace audio {
35
36 namespace {
37
38 const int kSampleRate = media::AudioParameters::kAudioCDSampleRate;
39 const media::ChannelLayout kChannelLayout = media::CHANNEL_LAYOUT_STEREO;
40 const int kSamplesPerPacket = kSampleRate / 100;
41
42 const double kMaxVolume = 1.0;
43
44 // InputController will poll once every second, so wait at most a bit
45 // more than that for the callbacks.
46 constexpr base::TimeDelta kOnMutePollInterval =
47 base::TimeDelta::FromMilliseconds(1000);
48
49 } // namespace
50
51 class MockInputControllerEventHandler : public InputController::EventHandler {
52 public:
53 MockInputControllerEventHandler() = default;
54
OnLog(base::StringPiece)55 void OnLog(base::StringPiece) override {}
56
57 MOCK_METHOD1(OnCreated, void(bool initially_muted));
58 MOCK_METHOD1(OnError, void(InputController::ErrorCode error_code));
59 MOCK_METHOD1(OnMuted, void(bool is_muted));
60
61 private:
62 DISALLOW_COPY_AND_ASSIGN(MockInputControllerEventHandler);
63 };
64
65 class MockSyncWriter : public InputController::SyncWriter {
66 public:
67 MockSyncWriter() = default;
68
69 MOCK_METHOD4(Write,
70 void(const media::AudioBus* data,
71 double volume,
72 bool key_pressed,
73 base::TimeTicks capture_time));
74 MOCK_METHOD0(Close, void());
75 };
76
77 class MockUserInputMonitor : public media::UserInputMonitor {
78 public:
79 MockUserInputMonitor() = default;
80
GetKeyPressCount() const81 uint32_t GetKeyPressCount() const override { return 0; }
82
83 MOCK_METHOD0(EnableKeyPressMonitoring, void());
84 MOCK_METHOD0(DisableKeyPressMonitoring, void());
85 };
86
87 class MockAudioInputStream : public media::AudioInputStream {
88 public:
MockAudioInputStream()89 MockAudioInputStream() {}
~MockAudioInputStream()90 ~MockAudioInputStream() override {}
91
Start(AudioInputCallback *)92 void Start(AudioInputCallback*) override {}
Stop()93 void Stop() override {}
Close()94 void Close() override {}
GetMaxVolume()95 double GetMaxVolume() override { return kMaxVolume; }
GetVolume()96 double GetVolume() override { return 0; }
SetAutomaticGainControl(bool)97 bool SetAutomaticGainControl(bool) override { return false; }
GetAutomaticGainControl()98 bool GetAutomaticGainControl() override { return false; }
IsMuted()99 bool IsMuted() override { return false; }
SetOutputDeviceForAec(const std::string &)100 void SetOutputDeviceForAec(const std::string&) override {}
101
102 MOCK_METHOD0(Open, bool());
103 MOCK_METHOD1(SetVolume, void(double));
104 };
105
106 // Parameter: use audio processing.
107 template <base::test::TaskEnvironment::TimeSource TimeSource =
108 base::test::TaskEnvironment::TimeSource::MOCK_TIME>
109 class TimeSourceInputControllerTest : public ::testing::TestWithParam<bool> {
110 public:
TimeSourceInputControllerTest()111 TimeSourceInputControllerTest()
112 : task_environment_(TimeSource),
113 audio_manager_(std::make_unique<media::FakeAudioManager>(
114 std::make_unique<media::TestAudioThread>(false),
115 &log_factory_)),
116 params_(media::AudioParameters::AUDIO_FAKE,
117 kChannelLayout,
118 kSampleRate,
119 kSamplesPerPacket) {
120 #if defined(AUDIO_PROCESSING_IN_AUDIO_SERVICE)
121 if (GetParam()) {
122 audio_processing_feature_.InitWithFeatures(
123 {features::kWebRtcApmInAudioService}, {});
124 }
125 #endif
126 }
127
~TimeSourceInputControllerTest()128 ~TimeSourceInputControllerTest() override {
129 audio_manager_->Shutdown();
130 task_environment_.RunUntilIdle();
131 }
132
133 protected:
CreateAudioController()134 void CreateAudioController() {
135 mojom::AudioProcessingConfigPtr config_ptr;
136 #if defined(AUDIO_PROCESSING_IN_AUDIO_SERVICE)
137 if (GetParam()) {
138 media::AudioProcessingSettings settings;
139 settings.echo_cancellation = media::EchoCancellationType::kAec3;
140 config_ptr = mojom::AudioProcessingConfigPtr(
141 base::in_place, remote_controls_.BindNewPipeAndPassReceiver(),
142 base::UnguessableToken::Create(), settings);
143 }
144 #endif
145
146 controller_ = InputController::Create(
147 audio_manager_.get(), &event_handler_, &sync_writer_,
148 &user_input_monitor_, params_,
149 media::AudioDeviceDescription::kDefaultDeviceId, false,
150 &stream_monitor_coordinator_, std::move(config_ptr));
151 }
152
153 base::test::TaskEnvironment task_environment_;
154
155 StreamMonitorCoordinator stream_monitor_coordinator_;
156 std::unique_ptr<InputController> controller_;
157 media::FakeAudioLogFactory log_factory_;
158 std::unique_ptr<media::AudioManager> audio_manager_;
159 MockInputControllerEventHandler event_handler_;
160 MockSyncWriter sync_writer_;
161 MockUserInputMonitor user_input_monitor_;
162 media::AudioParameters params_;
163 MockAudioInputStream stream_;
164 base::test::ScopedFeatureList audio_processing_feature_;
165 mojo::Remote<mojom::AudioProcessorControls> remote_controls_;
166
167 private:
168 DISALLOW_COPY_AND_ASSIGN(TimeSourceInputControllerTest);
169 };
170
171 using SystemTimeInputControllerTest = TimeSourceInputControllerTest<
172 base::test::TaskEnvironment::TimeSource::SYSTEM_TIME>;
173 using InputControllerTest = TimeSourceInputControllerTest<>;
174
TEST_P(InputControllerTest,CreateAndCloseWithoutRecording)175 TEST_P(InputControllerTest, CreateAndCloseWithoutRecording) {
176 EXPECT_CALL(event_handler_, OnCreated(_));
177 CreateAudioController();
178 task_environment_.RunUntilIdle();
179 ASSERT_TRUE(controller_.get());
180
181 EXPECT_CALL(sync_writer_, Close());
182 controller_->Close();
183 }
184
185 // Test a normal call sequence of create, record and close.
186 // Note: Must use system time as MOCK_TIME does not support the threads created
187 // by the FakeAudioInputStream. The callbacks to sync_writer_.Write() are on
188 // that thread, and thus we must use SYSTEM_TIME.
TEST_P(SystemTimeInputControllerTest,CreateRecordAndClose)189 TEST_P(SystemTimeInputControllerTest, CreateRecordAndClose) {
190 EXPECT_CALL(event_handler_, OnCreated(_));
191 CreateAudioController();
192 ASSERT_TRUE(controller_.get());
193
194 base::RunLoop loop;
195
196 {
197 // Wait for Write() to be called ten times.
198 testing::InSequence s;
199 EXPECT_CALL(user_input_monitor_, EnableKeyPressMonitoring());
200 EXPECT_CALL(sync_writer_, Write(NotNull(), _, _, _)).Times(Exactly(9));
201 EXPECT_CALL(sync_writer_, Write(NotNull(), _, _, _))
202 .Times(AtLeast(1))
203 .WillOnce(InvokeWithoutArgs([&]() { loop.Quit(); }));
204 }
205 controller_->Record();
206 loop.Run();
207
208 testing::Mock::VerifyAndClearExpectations(&user_input_monitor_);
209 testing::Mock::VerifyAndClearExpectations(&sync_writer_);
210
211 EXPECT_CALL(sync_writer_, Close());
212 EXPECT_CALL(user_input_monitor_, DisableKeyPressMonitoring());
213 controller_->Close();
214
215 task_environment_.RunUntilIdle();
216 }
217
TEST_P(InputControllerTest,CloseTwice)218 TEST_P(InputControllerTest, CloseTwice) {
219 EXPECT_CALL(event_handler_, OnCreated(_));
220 CreateAudioController();
221 ASSERT_TRUE(controller_.get());
222
223 EXPECT_CALL(user_input_monitor_, EnableKeyPressMonitoring());
224 controller_->Record();
225
226 EXPECT_CALL(user_input_monitor_, DisableKeyPressMonitoring());
227 EXPECT_CALL(sync_writer_, Close());
228 controller_->Close();
229
230 controller_->Close();
231 }
232
233 // Test that InputController sends OnMute callbacks properly.
TEST_P(InputControllerTest,TestOnmutedCallbackInitiallyUnmuted)234 TEST_P(InputControllerTest, TestOnmutedCallbackInitiallyUnmuted) {
235 WaitableEvent callback_event(WaitableEvent::ResetPolicy::AUTOMATIC,
236 WaitableEvent::InitialState::NOT_SIGNALED);
237
238 EXPECT_CALL(event_handler_, OnCreated(false));
239 EXPECT_CALL(sync_writer_, Close());
240
241 media::FakeAudioInputStream::SetGlobalMutedState(false);
242 CreateAudioController();
243 ASSERT_TRUE(controller_.get());
244 task_environment_.FastForwardBy(kOnMutePollInterval);
245
246 testing::Mock::VerifyAndClearExpectations(&event_handler_);
247 EXPECT_CALL(event_handler_, OnMuted(true));
248 media::FakeAudioInputStream::SetGlobalMutedState(true);
249 task_environment_.FastForwardBy(kOnMutePollInterval);
250
251 testing::Mock::VerifyAndClearExpectations(&event_handler_);
252 EXPECT_CALL(event_handler_, OnMuted(false));
253 media::FakeAudioInputStream::SetGlobalMutedState(false);
254 task_environment_.FastForwardBy(kOnMutePollInterval);
255
256 controller_->Close();
257 }
258
TEST_P(InputControllerTest,TestOnmutedCallbackInitiallyMuted)259 TEST_P(InputControllerTest, TestOnmutedCallbackInitiallyMuted) {
260 WaitableEvent callback_event(WaitableEvent::ResetPolicy::AUTOMATIC,
261 WaitableEvent::InitialState::NOT_SIGNALED);
262
263 EXPECT_CALL(event_handler_, OnCreated(true));
264 EXPECT_CALL(sync_writer_, Close());
265
266 media::FakeAudioInputStream::SetGlobalMutedState(true);
267 CreateAudioController();
268 ASSERT_TRUE(controller_.get());
269 task_environment_.FastForwardBy(kOnMutePollInterval);
270
271 testing::Mock::VerifyAndClearExpectations(&event_handler_);
272
273 EXPECT_CALL(event_handler_, OnMuted(false));
274 media::FakeAudioInputStream::SetGlobalMutedState(false);
275 task_environment_.FastForwardBy(kOnMutePollInterval);
276
277 controller_->Close();
278 }
279
280 #if defined(AUDIO_PROCESSING_IN_AUDIO_SERVICE)
281 INSTANTIATE_TEST_SUITE_P(All, InputControllerTest, ::testing::Bool());
282 INSTANTIATE_TEST_SUITE_P(All, SystemTimeInputControllerTest, ::testing::Bool());
283 #else
284 INSTANTIATE_TEST_SUITE_P(All, InputControllerTest, testing::Values(false));
285 INSTANTIATE_TEST_SUITE_P(All,
286 SystemTimeInputControllerTest,
287 ::testing::Values(false));
288 #endif
289
290 } // namespace audio
291