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 "content/browser/media/audio_input_stream_broker.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "base/sync_socket.h"
11 #include "base/test/mock_callback.h"
12 #include "content/public/test/browser_task_environment.h"
13 #include "media/mojo/mojom/audio_input_stream.mojom.h"
14 #include "mojo/public/cpp/bindings/pending_receiver.h"
15 #include "mojo/public/cpp/bindings/pending_remote.h"
16 #include "mojo/public/cpp/bindings/receiver.h"
17 #include "mojo/public/cpp/bindings/remote.h"
18 #include "services/audio/public/cpp/fake_stream_factory.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 using ::testing::Test;
23 using ::testing::Mock;
24 using ::testing::StrictMock;
25 using ::testing::InSequence;
26
27 namespace content {
28
29 namespace {
30
31 const int kRenderProcessId = 123;
32 const int kRenderFrameId = 234;
33 const uint32_t kShMemCount = 10;
34 const bool kEnableAgc = false;
35 const char kDeviceId[] = "testdeviceid";
36 const bool kInitiallyMuted = false;
37
TestParams()38 media::AudioParameters TestParams() {
39 return media::AudioParameters::UnavailableDeviceParams();
40 }
41
42 using MockDeleterCallback = StrictMock<
43 base::MockCallback<base::OnceCallback<void(AudioStreamBroker*)>>>;
44
45 class MockRendererAudioInputStreamFactoryClient
46 : public mojom::RendererAudioInputStreamFactoryClient {
47 public:
48 MockRendererAudioInputStreamFactoryClient() = default;
49 ~MockRendererAudioInputStreamFactoryClient() override = default;
50
51 mojo::PendingRemote<mojom::RendererAudioInputStreamFactoryClient>
MakeRemote()52 MakeRemote() {
53 return receiver_.BindNewPipeAndPassRemote();
54 }
55
56 MOCK_METHOD0(OnStreamCreated, void());
57
StreamCreated(mojo::PendingRemote<media::mojom::AudioInputStream> input_stream,mojo::PendingReceiver<media::mojom::AudioInputStreamClient> client_receiver,media::mojom::ReadOnlyAudioDataPipePtr data_pipe,bool initially_muted,const base::Optional<base::UnguessableToken> & stream_id)58 void StreamCreated(
59 mojo::PendingRemote<media::mojom::AudioInputStream> input_stream,
60 mojo::PendingReceiver<media::mojom::AudioInputStreamClient>
61 client_receiver,
62 media::mojom::ReadOnlyAudioDataPipePtr data_pipe,
63 bool initially_muted,
64 const base::Optional<base::UnguessableToken>& stream_id) override {
65 EXPECT_TRUE(stream_id.has_value());
66 input_stream_.Bind(std::move(input_stream));
67 client_receiver_ = std::move(client_receiver);
68 OnStreamCreated();
69 }
70
CloseReceiver()71 void CloseReceiver() { receiver_.reset(); }
72
73 private:
74 mojo::Receiver<mojom::RendererAudioInputStreamFactoryClient> receiver_{this};
75 mojo::Remote<media::mojom::AudioInputStream> input_stream_;
76 mojo::PendingReceiver<media::mojom::AudioInputStreamClient> client_receiver_;
77 DISALLOW_COPY_AND_ASSIGN(MockRendererAudioInputStreamFactoryClient);
78 };
79
80 class MockStreamFactory : public audio::FakeStreamFactory {
81 public:
MockStreamFactory()82 MockStreamFactory() {}
~MockStreamFactory()83 ~MockStreamFactory() final {}
84
85 // State of an expected stream creation. |device_id| and |params| are set
86 // ahead of time and verified during request. The other fields are filled in
87 // when the request is received.
88 struct StreamRequestData {
StreamRequestDatacontent::__anon864e636f0111::MockStreamFactory::StreamRequestData89 StreamRequestData(const std::string& device_id,
90 const media::AudioParameters& params)
91 : device_id(device_id), params(params) {}
92
93 bool requested = false;
94 mojo::PendingReceiver<media::mojom::AudioInputStream> stream_receiver;
95 mojo::Remote<media::mojom::AudioInputStreamClient> client;
96 mojo::Remote<media::mojom::AudioInputStreamObserver> observer;
97 mojo::Remote<media::mojom::AudioLog> log;
98 const std::string device_id;
99 const media::AudioParameters params;
100 uint32_t shared_memory_count;
101 bool enable_agc;
102 base::ReadOnlySharedMemoryRegion key_press_count_buffer;
103 CreateInputStreamCallback created_callback;
104 };
105
ExpectStreamCreation(StreamRequestData * ex)106 void ExpectStreamCreation(StreamRequestData* ex) {
107 stream_request_data_ = ex;
108 }
109
110 private:
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,audio::mojom::AudioProcessingConfigPtr processing_config,CreateInputStreamCallback created_callback)111 void CreateInputStream(
112 mojo::PendingReceiver<media::mojom::AudioInputStream> stream_receiver,
113 mojo::PendingRemote<media::mojom::AudioInputStreamClient> client,
114 mojo::PendingRemote<media::mojom::AudioInputStreamObserver> observer,
115 mojo::PendingRemote<media::mojom::AudioLog> log,
116 const std::string& device_id,
117 const media::AudioParameters& params,
118 uint32_t shared_memory_count,
119 bool enable_agc,
120 base::ReadOnlySharedMemoryRegion key_press_count_buffer,
121 audio::mojom::AudioProcessingConfigPtr processing_config,
122 CreateInputStreamCallback created_callback) override {
123 // No way to cleanly exit the test here in case of failure, so use CHECK.
124 CHECK(stream_request_data_);
125 EXPECT_EQ(stream_request_data_->device_id, device_id);
126 EXPECT_TRUE(stream_request_data_->params.Equals(params));
127 stream_request_data_->requested = true;
128 stream_request_data_->stream_receiver = std::move(stream_receiver);
129 stream_request_data_->client.Bind(std::move(client));
130 stream_request_data_->observer.Bind(std::move(observer));
131 stream_request_data_->log.Bind(std::move(log));
132 stream_request_data_->shared_memory_count = shared_memory_count;
133 stream_request_data_->enable_agc = enable_agc;
134 stream_request_data_->key_press_count_buffer =
135 std::move(key_press_count_buffer);
136 stream_request_data_->created_callback = std::move(created_callback);
137 }
138
139 StreamRequestData* stream_request_data_;
140 DISALLOW_COPY_AND_ASSIGN(MockStreamFactory);
141 };
142
143 struct TestEnvironment {
TestEnvironmentcontent::__anon864e636f0111::TestEnvironment144 TestEnvironment()
145 : broker(std::make_unique<AudioInputStreamBroker>(
146 kRenderProcessId,
147 kRenderFrameId,
148 kDeviceId,
149 TestParams(),
150 kShMemCount,
151 nullptr /*user_input_monitor*/,
152 kEnableAgc,
153 nullptr,
154 deleter.Get(),
155 renderer_factory_client.MakeRemote())) {}
156
RunUntilIdlecontent::__anon864e636f0111::TestEnvironment157 void RunUntilIdle() { task_environment.RunUntilIdle(); }
158
159 BrowserTaskEnvironment task_environment;
160 MockDeleterCallback deleter;
161 StrictMock<MockRendererAudioInputStreamFactoryClient> renderer_factory_client;
162 std::unique_ptr<AudioInputStreamBroker> broker;
163 MockStreamFactory stream_factory;
164 mojo::Remote<audio::mojom::StreamFactory> factory_ptr{
165 stream_factory.MakeRemote()};
166 };
167
168 } // namespace
169
TEST(AudioInputStreamBrokerTest,StoresProcessAndFrameId)170 TEST(AudioInputStreamBrokerTest, StoresProcessAndFrameId) {
171 BrowserTaskEnvironment task_environment;
172 MockDeleterCallback deleter;
173 StrictMock<MockRendererAudioInputStreamFactoryClient> renderer_factory_client;
174
175 AudioInputStreamBroker broker(
176 kRenderProcessId, kRenderFrameId, kDeviceId, TestParams(), kShMemCount,
177 nullptr /*user_input_monitor*/, kEnableAgc, nullptr, deleter.Get(),
178 renderer_factory_client.MakeRemote());
179
180 EXPECT_EQ(kRenderProcessId, broker.render_process_id());
181 EXPECT_EQ(kRenderFrameId, broker.render_frame_id());
182 }
183
TEST(AudioInputStreamBrokerTest,StreamCreationSuccess_Propagates)184 TEST(AudioInputStreamBrokerTest, StreamCreationSuccess_Propagates) {
185 TestEnvironment env;
186 MockStreamFactory::StreamRequestData stream_request_data(kDeviceId,
187 TestParams());
188 env.stream_factory.ExpectStreamCreation(&stream_request_data);
189
190 env.broker->CreateStream(env.factory_ptr.get());
191 env.RunUntilIdle();
192
193 EXPECT_TRUE(stream_request_data.requested);
194
195 // Set up test IPC primitives.
196 const size_t shmem_size = 456;
197 base::SyncSocket socket1, socket2;
198 base::SyncSocket::CreatePair(&socket1, &socket2);
199 std::move(stream_request_data.created_callback)
200 .Run({base::in_place,
201 base::ReadOnlySharedMemoryRegion::Create(shmem_size).region,
202 mojo::PlatformHandle(socket1.Take())},
203 kInitiallyMuted, base::UnguessableToken::Create());
204
205 EXPECT_CALL(env.renderer_factory_client, OnStreamCreated());
206
207 env.RunUntilIdle();
208
209 Mock::VerifyAndClear(&env.renderer_factory_client);
210
211 env.broker.reset();
212 }
213
TEST(AudioInputStreamBrokerTest,StreamCreationFailure_CallsDeleter)214 TEST(AudioInputStreamBrokerTest, StreamCreationFailure_CallsDeleter) {
215 TestEnvironment env;
216 MockStreamFactory::StreamRequestData stream_request_data(kDeviceId,
217 TestParams());
218 env.stream_factory.ExpectStreamCreation(&stream_request_data);
219
220 env.broker->CreateStream(env.factory_ptr.get());
221 env.RunUntilIdle();
222
223 EXPECT_TRUE(stream_request_data.requested);
224 EXPECT_CALL(env.deleter, Run(env.broker.release()))
225 .WillOnce(testing::DeleteArg<0>());
226
227 std::move(stream_request_data.created_callback)
228 .Run(nullptr, kInitiallyMuted, base::nullopt);
229
230 env.RunUntilIdle();
231 }
232
TEST(AudioInputStreamBrokerTest,RendererFactoryClientDisconnect_CallsDeleter)233 TEST(AudioInputStreamBrokerTest, RendererFactoryClientDisconnect_CallsDeleter) {
234 InSequence seq;
235 TestEnvironment env;
236 MockStreamFactory::StreamRequestData stream_request_data(kDeviceId,
237 TestParams());
238 env.stream_factory.ExpectStreamCreation(&stream_request_data);
239
240 env.broker->CreateStream(env.factory_ptr.get());
241 env.RunUntilIdle();
242 EXPECT_TRUE(stream_request_data.requested);
243
244 EXPECT_CALL(env.deleter, Run(env.broker.release()))
245 .WillOnce(testing::DeleteArg<0>());
246 env.renderer_factory_client.CloseReceiver();
247 env.RunUntilIdle();
248 Mock::VerifyAndClear(&env.deleter);
249
250 env.stream_factory.ResetReceiver();
251 env.RunUntilIdle();
252 }
253
TEST(AudioInputStreamBrokerTest,ObserverDisconnect_CallsDeleter)254 TEST(AudioInputStreamBrokerTest, ObserverDisconnect_CallsDeleter) {
255 InSequence seq;
256 TestEnvironment env;
257 MockStreamFactory::StreamRequestData stream_request_data(kDeviceId,
258 TestParams());
259 env.stream_factory.ExpectStreamCreation(&stream_request_data);
260
261 env.broker->CreateStream(env.factory_ptr.get());
262 env.RunUntilIdle();
263 EXPECT_TRUE(stream_request_data.requested);
264
265 EXPECT_CALL(env.deleter, Run(env.broker.release()))
266 .WillOnce(testing::DeleteArg<0>());
267 stream_request_data.observer.reset();
268 env.RunUntilIdle();
269 Mock::VerifyAndClear(&env.deleter);
270
271 env.stream_factory.ResetReceiver();
272 env.RunUntilIdle();
273 }
274
TEST(AudioInputStreamBrokerTest,FactoryDisconnectDuringConstruction_CallsDeleter)275 TEST(AudioInputStreamBrokerTest,
276 FactoryDisconnectDuringConstruction_CallsDeleter) {
277 TestEnvironment env;
278
279 env.broker->CreateStream(env.factory_ptr.get());
280 env.stream_factory.ResetReceiver();
281
282 EXPECT_CALL(env.deleter, Run(env.broker.release()))
283 .WillOnce(testing::DeleteArg<0>());
284
285 env.RunUntilIdle();
286 }
287
288 } // namespace content
289