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