1 // Copyright 2017 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 "media/mojo/services/mojo_audio_input_stream.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/memory/read_only_shared_memory_region.h"
12 #include "base/run_loop.h"
13 #include "base/sync_socket.h"
14 #include "base/test/task_environment.h"
15 #include "mojo/public/cpp/bindings/receiver.h"
16 #include "mojo/public/cpp/bindings/remote.h"
17 #include "mojo/public/cpp/system/platform_handle.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 
21 namespace media {
22 
23 namespace {
24 
25 const double kNewVolume = 0.618;
26 // Not actually used, but sent from the AudioInputDelegate.
27 const int kStreamId = 0;
28 const int kShmemSize = 100;
29 // const bool kInitiallyMuted = true;
30 const bool kInitiallyNotMuted = true;
31 
32 using testing::_;
33 using testing::Mock;
34 using testing::NotNull;
35 using testing::Return;
36 using testing::SaveArg;
37 using testing::StrictMock;
38 using testing::Test;
39 using AudioInputStream = mojom::AudioInputStream;
40 
41 class TestCancelableSyncSocket : public base::CancelableSyncSocket {
42  public:
43   TestCancelableSyncSocket() = default;
44 
ExpectOwnershipTransfer()45   void ExpectOwnershipTransfer() { expect_ownership_transfer_ = true; }
46 
~TestCancelableSyncSocket()47   ~TestCancelableSyncSocket() override {
48     // When the handle is sent over mojo, mojo takes ownership over it and
49     // closes it. We have to make sure we do not also retain the handle in the
50     // sync socket, as the sync socket closes the handle on destruction.
51     if (expect_ownership_transfer_)
52       EXPECT_FALSE(IsValid());
53   }
54 
55  private:
56   bool expect_ownership_transfer_ = false;
57 
58   DISALLOW_COPY_AND_ASSIGN(TestCancelableSyncSocket);
59 };
60 
61 class MockDelegate : public AudioInputDelegate {
62  public:
63   MockDelegate() = default;
64   ~MockDelegate() override = default;
65 
66   MOCK_METHOD0(GetStreamId, int());
67   MOCK_METHOD0(OnRecordStream, void());
68   MOCK_METHOD1(OnSetVolume, void(double));
69   MOCK_METHOD1(OnSetOutputDeviceForAec, void(const std::string&));
70 };
71 
72 class MockDelegateFactory {
73  public:
PrepareDelegateForCreation(std::unique_ptr<AudioInputDelegate> delegate)74   void PrepareDelegateForCreation(
75       std::unique_ptr<AudioInputDelegate> delegate) {
76     ASSERT_EQ(nullptr, delegate_);
77     delegate_.swap(delegate);
78   }
79 
CreateDelegate(AudioInputDelegate::EventHandler * handler)80   std::unique_ptr<AudioInputDelegate> CreateDelegate(
81       AudioInputDelegate::EventHandler* handler) {
82     MockCreateDelegate(handler);
83     EXPECT_NE(nullptr, delegate_);
84     return std::move(delegate_);
85   }
86 
87   MOCK_METHOD1(MockCreateDelegate, void(AudioInputDelegate::EventHandler*));
88 
89  private:
90   std::unique_ptr<AudioInputDelegate> delegate_;
91 };
92 
93 class MockDeleter {
94  public:
95   MOCK_METHOD0(Finished, void());
96 };
97 
98 class MockClient : public mojom::AudioInputStreamClient {
99  public:
100   MockClient() = default;
101 
Initialized(mojom::ReadOnlyAudioDataPipePtr data_pipe,bool initially_muted)102   void Initialized(mojom::ReadOnlyAudioDataPipePtr data_pipe,
103                    bool initially_muted) {
104     ASSERT_TRUE(data_pipe->shared_memory.IsValid());
105     ASSERT_TRUE(data_pipe->socket.is_valid());
106 
107     socket_ = std::make_unique<base::CancelableSyncSocket>(
108         data_pipe->socket.TakePlatformFile());
109     EXPECT_TRUE(socket_->IsValid());
110 
111     region_ = std::move(data_pipe->shared_memory);
112     EXPECT_TRUE(region_.IsValid());
113 
114     GotNotification(initially_muted);
115   }
116 
117   MOCK_METHOD1(GotNotification, void(bool initially_muted));
118 
119   MOCK_METHOD1(OnMutedStateChanged, void(bool));
120 
121   MOCK_METHOD0(OnError, void());
122 
123  private:
124   base::ReadOnlySharedMemoryRegion region_;
125   std::unique_ptr<base::CancelableSyncSocket> socket_;
126 
127   DISALLOW_COPY_AND_ASSIGN(MockClient);
128 };
129 
CreateNoDelegate(AudioInputDelegate::EventHandler * event_handler)130 std::unique_ptr<AudioInputDelegate> CreateNoDelegate(
131     AudioInputDelegate::EventHandler* event_handler) {
132   return nullptr;
133 }
134 
NotCalled(mojom::ReadOnlyAudioDataPipePtr data_pipe,bool initially_muted)135 void NotCalled(mojom::ReadOnlyAudioDataPipePtr data_pipe,
136                bool initially_muted) {
137   EXPECT_TRUE(false) << "The StreamCreated callback was called despite the "
138                         "test expecting it not to.";
139 }
140 
141 }  // namespace
142 
143 class MojoAudioInputStreamTest : public Test {
144  public:
MojoAudioInputStreamTest()145   MojoAudioInputStreamTest()
146       : foreign_socket_(std::make_unique<TestCancelableSyncSocket>()),
147         client_receiver_(&client_) {}
148 
CreateAudioInput()149   mojo::Remote<mojom::AudioInputStream> CreateAudioInput() {
150     mojo::Remote<mojom::AudioInputStream> stream;
151     ExpectDelegateCreation();
152     impl_ = std::make_unique<MojoAudioInputStream>(
153         stream.BindNewPipeAndPassReceiver(),
154         client_receiver_.BindNewPipeAndPassRemote(),
155         base::BindOnce(&MockDelegateFactory::CreateDelegate,
156                        base::Unretained(&mock_delegate_factory_)),
157         base::BindOnce(&MockClient::Initialized, base::Unretained(&client_)),
158         base::BindOnce(&MockDeleter::Finished, base::Unretained(&deleter_)));
159     EXPECT_TRUE(stream.is_bound());
160     return stream;
161   }
162 
163  protected:
ExpectDelegateCreation()164   void ExpectDelegateCreation() {
165     delegate_ = new StrictMock<MockDelegate>();
166     mock_delegate_factory_.PrepareDelegateForCreation(
167         base::WrapUnique(delegate_));
168     EXPECT_TRUE(
169         base::CancelableSyncSocket::CreatePair(&local_, foreign_socket_.get()));
170     mem_ = base::ReadOnlySharedMemoryRegion::Create(kShmemSize).region;
171     EXPECT_TRUE(mem_.IsValid());
172     EXPECT_CALL(mock_delegate_factory_, MockCreateDelegate(NotNull()))
173         .WillOnce(SaveArg<0>(&delegate_event_handler_));
174   }
175 
176   base::test::SingleThreadTaskEnvironment task_environment_;
177   base::CancelableSyncSocket local_;
178   std::unique_ptr<TestCancelableSyncSocket> foreign_socket_;
179   base::ReadOnlySharedMemoryRegion mem_;
180   StrictMock<MockDelegate>* delegate_ = nullptr;
181   AudioInputDelegate::EventHandler* delegate_event_handler_ = nullptr;
182   StrictMock<MockDelegateFactory> mock_delegate_factory_;
183   StrictMock<MockDeleter> deleter_;
184   StrictMock<MockClient> client_;
185   mojo::Receiver<media::mojom::AudioInputStreamClient> client_receiver_;
186   std::unique_ptr<MojoAudioInputStream> impl_;
187 
188   DISALLOW_COPY_AND_ASSIGN(MojoAudioInputStreamTest);
189 };
190 
TEST_F(MojoAudioInputStreamTest,NoDelegate_SignalsError)191 TEST_F(MojoAudioInputStreamTest, NoDelegate_SignalsError) {
192   bool deleter_called = false;
193   EXPECT_CALL(client_, OnError());
194   mojo::Remote<mojom::AudioInputStream> stream_remote;
195   MojoAudioInputStream stream(
196       stream_remote.BindNewPipeAndPassReceiver(),
197       client_receiver_.BindNewPipeAndPassRemote(),
198       base::BindOnce(&CreateNoDelegate), base::BindOnce(&NotCalled),
199       base::BindOnce([](bool* p) { *p = true; }, &deleter_called));
200   EXPECT_FALSE(deleter_called)
201       << "Stream shouldn't call the deleter from its constructor.";
202   base::RunLoop().RunUntilIdle();
203   EXPECT_TRUE(deleter_called);
204 }
205 
TEST_F(MojoAudioInputStreamTest,Record_Records)206 TEST_F(MojoAudioInputStreamTest, Record_Records) {
207   auto audio_input = CreateAudioInput();
208   EXPECT_CALL(*delegate_, OnRecordStream());
209 
210   audio_input->Record();
211   base::RunLoop().RunUntilIdle();
212 }
213 
TEST_F(MojoAudioInputStreamTest,SetVolume_SetsVolume)214 TEST_F(MojoAudioInputStreamTest, SetVolume_SetsVolume) {
215   auto audio_input = CreateAudioInput();
216   EXPECT_CALL(*delegate_, OnSetVolume(kNewVolume));
217 
218   audio_input->SetVolume(kNewVolume);
219   base::RunLoop().RunUntilIdle();
220 }
221 
TEST_F(MojoAudioInputStreamTest,DestructWithCallPending_Safe)222 TEST_F(MojoAudioInputStreamTest, DestructWithCallPending_Safe) {
223   auto audio_input = CreateAudioInput();
224   EXPECT_CALL(client_, GotNotification(kInitiallyNotMuted));
225   base::RunLoop().RunUntilIdle();
226 
227   ASSERT_NE(nullptr, delegate_event_handler_);
228   foreign_socket_->ExpectOwnershipTransfer();
229   delegate_event_handler_->OnStreamCreated(kStreamId, std::move(mem_),
230                                            std::move(foreign_socket_),
231                                            kInitiallyNotMuted);
232   audio_input->Record();
233   impl_.reset();
234   base::RunLoop().RunUntilIdle();
235 }
236 
TEST_F(MojoAudioInputStreamTest,Created_NotifiesClient)237 TEST_F(MojoAudioInputStreamTest, Created_NotifiesClient) {
238   auto audio_input = CreateAudioInput();
239   base::RunLoop().RunUntilIdle();
240 
241   EXPECT_CALL(client_, GotNotification(kInitiallyNotMuted));
242 
243   ASSERT_NE(nullptr, delegate_event_handler_);
244   foreign_socket_->ExpectOwnershipTransfer();
245   delegate_event_handler_->OnStreamCreated(kStreamId, std::move(mem_),
246                                            std::move(foreign_socket_),
247                                            kInitiallyNotMuted);
248 
249   base::RunLoop().RunUntilIdle();
250 }
251 
TEST_F(MojoAudioInputStreamTest,SetVolumeTooLarge_Error)252 TEST_F(MojoAudioInputStreamTest, SetVolumeTooLarge_Error) {
253   auto audio_input = CreateAudioInput();
254   EXPECT_CALL(deleter_, Finished());
255   EXPECT_CALL(client_, OnError());
256 
257   audio_input->SetVolume(15);
258   base::RunLoop().RunUntilIdle();
259   Mock::VerifyAndClear(&deleter_);
260 }
261 
TEST_F(MojoAudioInputStreamTest,SetVolumeNegative_Error)262 TEST_F(MojoAudioInputStreamTest, SetVolumeNegative_Error) {
263   auto audio_input = CreateAudioInput();
264   EXPECT_CALL(deleter_, Finished());
265   EXPECT_CALL(client_, OnError());
266 
267   audio_input->SetVolume(-0.5);
268   base::RunLoop().RunUntilIdle();
269   Mock::VerifyAndClear(&deleter_);
270 }
271 
TEST_F(MojoAudioInputStreamTest,DelegateErrorBeforeCreated_PropagatesError)272 TEST_F(MojoAudioInputStreamTest, DelegateErrorBeforeCreated_PropagatesError) {
273   auto audio_input = CreateAudioInput();
274   EXPECT_CALL(deleter_, Finished());
275   EXPECT_CALL(client_, OnError());
276 
277   ASSERT_NE(nullptr, delegate_event_handler_);
278   delegate_event_handler_->OnStreamError(kStreamId);
279 
280   base::RunLoop().RunUntilIdle();
281   Mock::VerifyAndClear(&deleter_);
282 }
283 
TEST_F(MojoAudioInputStreamTest,DelegateErrorAfterCreated_PropagatesError)284 TEST_F(MojoAudioInputStreamTest, DelegateErrorAfterCreated_PropagatesError) {
285   auto audio_input = CreateAudioInput();
286   EXPECT_CALL(client_, GotNotification(kInitiallyNotMuted));
287   EXPECT_CALL(deleter_, Finished());
288   EXPECT_CALL(client_, OnError());
289   base::RunLoop().RunUntilIdle();
290 
291   ASSERT_NE(nullptr, delegate_event_handler_);
292   foreign_socket_->ExpectOwnershipTransfer();
293   delegate_event_handler_->OnStreamCreated(kStreamId, std::move(mem_),
294                                            std::move(foreign_socket_),
295                                            kInitiallyNotMuted);
296   delegate_event_handler_->OnStreamError(kStreamId);
297 
298   base::RunLoop().RunUntilIdle();
299   Mock::VerifyAndClear(&deleter_);
300 }
301 
TEST_F(MojoAudioInputStreamTest,RemoteEndGone_Error)302 TEST_F(MojoAudioInputStreamTest, RemoteEndGone_Error) {
303   auto audio_input = CreateAudioInput();
304   EXPECT_CALL(deleter_, Finished());
305   audio_input.reset();
306   base::RunLoop().RunUntilIdle();
307   Mock::VerifyAndClear(&deleter_);
308 }
309 
310 }  // namespace media
311