1 // Copyright 2018 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/public/cpp/input_ipc.h"
6
7 #include <string>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/test/task_environment.h"
12 #include "media/mojo/mojom/audio_data_pipe.mojom.h"
13 #include "mojo/public/cpp/bindings/receiver.h"
14 #include "mojo/public/cpp/bindings/remote.h"
15 #include "mojo/public/cpp/system/buffer.h"
16 #include "mojo/public/cpp/system/platform_handle.h"
17 #include "services/audio/public/cpp/device_factory.h"
18 #include "services/audio/public/cpp/fake_stream_factory.h"
19 #include "services/audio/public/mojom/audio_processing.mojom.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 using testing::_;
24 using testing::StrictMock;
25
26 namespace audio {
27
28 namespace {
29
30 const char kDeviceId[] = "1234";
31 const size_t kShMemSize = 456;
32 const double kNewVolume = 0.271828;
33
34 class MockStream : public media::mojom::AudioInputStream {
35 public:
36 MOCK_METHOD0(Record, void());
37 MOCK_METHOD1(SetVolume, void(double));
38 };
39
40 class TestStreamFactory : public audio::FakeStreamFactory {
41 public:
TestStreamFactory()42 TestStreamFactory() : stream_(), stream_receiver_(&stream_) {}
43 ~TestStreamFactory() override = default;
CreateInputStream(mojo::PendingReceiver<media::mojom::AudioInputStream> stream_receiver,mojo::PendingRemote<media::mojom::AudioInputStreamClient> client,mojo::PendingRemote<media::mojom::AudioInputStreamObserver> observer,mojo::PendingRemote<media::mojom::AudioLog> log,const std::string & device_id,const media::AudioParameters & params,uint32_t shared_memory_count,bool enable_agc,base::ReadOnlySharedMemoryRegion key_press_count_buffer,mojom::AudioProcessingConfigPtr processing_config,CreateInputStreamCallback created_callback)44 void CreateInputStream(
45 mojo::PendingReceiver<media::mojom::AudioInputStream> stream_receiver,
46 mojo::PendingRemote<media::mojom::AudioInputStreamClient> client,
47 mojo::PendingRemote<media::mojom::AudioInputStreamObserver> observer,
48 mojo::PendingRemote<media::mojom::AudioLog> log,
49 const std::string& device_id,
50 const media::AudioParameters& params,
51 uint32_t shared_memory_count,
52 bool enable_agc,
53 base::ReadOnlySharedMemoryRegion key_press_count_buffer,
54 mojom::AudioProcessingConfigPtr processing_config,
55 CreateInputStreamCallback created_callback) {
56 if (should_fail_) {
57 std::move(created_callback).Run(nullptr, initially_muted_, base::nullopt);
58 return;
59 }
60
61 if (client_)
62 client_.reset();
63 // Keep the passed client alive to avoid binding errors.
64 client_.Bind(std::move(client));
65
66 if (stream_receiver_.is_bound())
67 stream_receiver_.reset();
68 stream_receiver_.Bind(std::move(stream_receiver));
69
70 base::SyncSocket socket1, socket2;
71 base::SyncSocket::CreatePair(&socket1, &socket2);
72 std::move(created_callback)
73 .Run({base::in_place,
74 base::ReadOnlySharedMemoryRegion::Create(kShMemSize).region,
75 mojo::PlatformHandle(socket1.Take())},
76 initially_muted_, base::UnguessableToken::Create());
77 }
78
79 MOCK_METHOD2(AssociateInputAndOutputForAec,
80 void(const base::UnguessableToken& input_stream_id,
81 const std::string& output_device_id));
82
MakeRemote()83 mojo::PendingRemote<audio::mojom::StreamFactory> MakeRemote() {
84 return receiver_.BindNewPipeAndPassRemote();
85 }
86
87 StrictMock<MockStream> stream_;
88 mojo::Remote<media::mojom::AudioInputStreamClient> client_;
89 mojo::Receiver<media::mojom::AudioInputStream> stream_receiver_;
90 bool initially_muted_ = true;
91 bool should_fail_ = false;
92 };
93
94 class MockDelegate : public media::AudioInputIPCDelegate {
95 public:
96 MockDelegate() = default;
97 ~MockDelegate() override = default;
98
OnStreamCreated(base::ReadOnlySharedMemoryRegion mem_handle,base::SyncSocket::ScopedHandle socket_handle,bool initially_muted)99 void OnStreamCreated(base::ReadOnlySharedMemoryRegion mem_handle,
100 base::SyncSocket::ScopedHandle socket_handle,
101 bool initially_muted) override {
102 GotOnStreamCreated(initially_muted);
103 }
104
105 MOCK_METHOD1(GotOnStreamCreated, void(bool initially_muted));
106 MOCK_METHOD0(OnError, void());
107 MOCK_METHOD1(OnMuted, void(bool));
108 MOCK_METHOD0(OnIPCClosed, void());
109 };
110
111 class InputIPCTest : public ::testing::Test {
112 public:
113 base::test::TaskEnvironment task_environment;
114 std::unique_ptr<audio::InputIPC> ipc;
115 const media::AudioParameters audioParameters =
116 media::AudioParameters(media::AudioParameters::AUDIO_PCM_LINEAR,
117 media::CHANNEL_LAYOUT_STEREO,
118 16000,
119 1600);
120
121 protected:
InputIPCTest()122 InputIPCTest()
123 : task_environment(
124 base::test::TaskEnvironment::MainThreadType::DEFAULT,
125 base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED) {}
126 std::unique_ptr<StrictMock<TestStreamFactory>> factory_;
127
SetUp()128 void SetUp() override {
129 factory_ = std::make_unique<StrictMock<TestStreamFactory>>();
130 ipc = std::make_unique<InputIPC>(factory_->MakeRemote(), kDeviceId,
131 mojo::NullRemote());
132 }
133 };
134
135 } // namespace
136
TEST_F(InputIPCTest,CreateStreamPropagates)137 TEST_F(InputIPCTest, CreateStreamPropagates) {
138 StrictMock<MockDelegate> delegate;
139 EXPECT_CALL(delegate, GotOnStreamCreated(_));
140 ipc->CreateStream(&delegate, audioParameters, false, 0);
141 task_environment.RunUntilIdle();
142 }
143
TEST_F(InputIPCTest,StreamCreatedAfterCloseIsIgnored)144 TEST_F(InputIPCTest, StreamCreatedAfterCloseIsIgnored) {
145 StrictMock<MockDelegate> delegate;
146 ipc->CreateStream(&delegate, audioParameters, false, 0);
147 ipc->CloseStream();
148 task_environment.RunUntilIdle();
149 }
150
TEST_F(InputIPCTest,CreateStreamPropagatesInitiallyMuted)151 TEST_F(InputIPCTest, CreateStreamPropagatesInitiallyMuted) {
152 StrictMock<MockDelegate> delegate;
153
154 factory_->initially_muted_ = true;
155 EXPECT_CALL(delegate, GotOnStreamCreated(true));
156 ipc->CreateStream(&delegate, audioParameters, false, 0);
157 task_environment.RunUntilIdle();
158 ipc->CloseStream();
159 task_environment.RunUntilIdle();
160
161 factory_->initially_muted_ = false;
162 EXPECT_CALL(delegate, GotOnStreamCreated(false));
163 ipc->CreateStream(&delegate, audioParameters, false, 0);
164 task_environment.RunUntilIdle();
165 ipc->CloseStream();
166 task_environment.RunUntilIdle();
167 }
168
TEST_F(InputIPCTest,MutedStateChangesPropagates)169 TEST_F(InputIPCTest, MutedStateChangesPropagates) {
170 StrictMock<MockDelegate> delegate;
171
172 EXPECT_CALL(delegate, GotOnStreamCreated(_));
173 ipc->CreateStream(&delegate, audioParameters, false, 0);
174 task_environment.RunUntilIdle();
175
176 EXPECT_CALL(delegate, OnMuted(true));
177 factory_->client_->OnMutedStateChanged(true);
178 task_environment.RunUntilIdle();
179
180 EXPECT_CALL(delegate, OnMuted(false));
181 factory_->client_->OnMutedStateChanged(false);
182 task_environment.RunUntilIdle();
183 }
184
TEST_F(InputIPCTest,Record_Records)185 TEST_F(InputIPCTest, Record_Records) {
186 StrictMock<MockDelegate> delegate;
187 EXPECT_CALL(delegate, GotOnStreamCreated(_));
188 ipc->CreateStream(&delegate, audioParameters, false, 0);
189 task_environment.RunUntilIdle();
190
191 EXPECT_CALL(factory_->stream_, Record());
192 ipc->RecordStream();
193 task_environment.RunUntilIdle();
194 }
195
TEST_F(InputIPCTest,IsReusable)196 TEST_F(InputIPCTest, IsReusable) {
197 for (int i = 0; i < 5; i++) {
198 StrictMock<MockDelegate> delegate;
199 EXPECT_CALL(delegate, GotOnStreamCreated(_));
200 ipc->CreateStream(&delegate, audioParameters, false, 0);
201 task_environment.RunUntilIdle();
202
203 ipc->CloseStream();
204 task_environment.RunUntilIdle();
205
206 testing::Mock::VerifyAndClearExpectations(&delegate);
207 }
208 }
209
TEST_F(InputIPCTest,SetVolume_SetsVolume)210 TEST_F(InputIPCTest, SetVolume_SetsVolume) {
211 StrictMock<MockDelegate> delegate;
212 EXPECT_CALL(delegate, GotOnStreamCreated(_));
213 ipc->CreateStream(&delegate, audioParameters, false, 0);
214 task_environment.RunUntilIdle();
215
216 EXPECT_CALL(factory_->stream_, SetVolume(kNewVolume));
217 ipc->SetVolume(kNewVolume);
218 task_environment.RunUntilIdle();
219 }
220
TEST_F(InputIPCTest,SetOutputDeviceForAec_AssociatesInputAndOutputForAec)221 TEST_F(InputIPCTest, SetOutputDeviceForAec_AssociatesInputAndOutputForAec) {
222 const std::string kOutputDeviceId = "2345";
223 StrictMock<MockDelegate> delegate;
224 EXPECT_CALL(delegate, GotOnStreamCreated(_));
225 ipc->CreateStream(&delegate, audioParameters, false, 0);
226 task_environment.RunUntilIdle();
227
228 EXPECT_CALL(*factory_, AssociateInputAndOutputForAec(_, kOutputDeviceId));
229 ipc->SetOutputDeviceForAec(kOutputDeviceId);
230 task_environment.RunUntilIdle();
231 }
232
TEST_F(InputIPCTest,FailedStreamCreationNullCallback)233 TEST_F(InputIPCTest, FailedStreamCreationNullCallback) {
234 StrictMock<MockDelegate> delegate;
235 EXPECT_CALL(delegate, OnError()).Times(2);
236 factory_->should_fail_ = true;
237 ipc->CreateStream(&delegate, audioParameters, false, 0);
238 task_environment.RunUntilIdle();
239 }
240
TEST_F(InputIPCTest,FailedStreamCreationDestuctedFactory)241 TEST_F(InputIPCTest, FailedStreamCreationDestuctedFactory) {
242 StrictMock<MockDelegate> delegate;
243 EXPECT_CALL(delegate, OnError());
244 factory_ = nullptr;
245 ipc->CreateStream(&delegate, audioParameters, false, 0);
246 task_environment.RunUntilIdle();
247 }
248
249 } // namespace audio
250