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