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