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_output_stream.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/memory/unsafe_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 "media/mojo/mojom/audio_data_pipe.mojom.h"
16 #include "mojo/public/cpp/bindings/pending_receiver.h"
17 #include "mojo/public/cpp/bindings/pending_remote.h"
18 #include "mojo/public/cpp/bindings/remote.h"
19 #include "mojo/public/cpp/system/message_pipe.h"
20 #include "mojo/public/cpp/system/platform_handle.h"
21 #include "testing/gmock/include/gmock/gmock.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 
24 namespace media {
25 
26 namespace {
27 
28 const double kNewVolume = 0.618;
29 // Not actually used, but sent from the AudioOutputDelegate.
30 const int kStreamId = 0;
31 const int kShmemSize = 100;
32 
33 using testing::_;
34 using testing::Mock;
35 using testing::NotNull;
36 using testing::Return;
37 using testing::SaveArg;
38 using testing::StrictMock;
39 using testing::Test;
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 AudioOutputDelegate {
62  public:
63   MockDelegate() = default;
64   ~MockDelegate() override = default;
65 
66   MOCK_METHOD0(GetStreamId, int());
67   MOCK_METHOD0(OnPlayStream, void());
68   MOCK_METHOD0(OnPauseStream, void());
69   MOCK_METHOD1(OnSetVolume, void(double));
70   MOCK_METHOD0(OnFlushStream, void());
71 };
72 
73 class MockDelegateFactory {
74  public:
PrepareDelegateForCreation(std::unique_ptr<AudioOutputDelegate> delegate)75   void PrepareDelegateForCreation(
76       std::unique_ptr<AudioOutputDelegate> delegate) {
77     ASSERT_EQ(nullptr, delegate_);
78     delegate_.swap(delegate);
79   }
80 
CreateDelegate(AudioOutputDelegate::EventHandler * handler)81   std::unique_ptr<AudioOutputDelegate> CreateDelegate(
82       AudioOutputDelegate::EventHandler* handler) {
83     MockCreateDelegate(handler);
84     EXPECT_NE(nullptr, delegate_);
85     return std::move(delegate_);
86   }
87 
88   MOCK_METHOD1(MockCreateDelegate, void(AudioOutputDelegate::EventHandler*));
89 
90  private:
91   std::unique_ptr<AudioOutputDelegate> delegate_;
92 };
93 
94 class MockDeleter {
95  public:
96   MOCK_METHOD1(Finished, void(bool));
97 };
98 
99 class MockClient {
100  public:
101   MockClient() = default;
102 
Initialize(mojom::ReadWriteAudioDataPipePtr data_pipe)103   void Initialize(mojom::ReadWriteAudioDataPipePtr data_pipe) {
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     shared_memory_region_ = std::move(data_pipe->shared_memory);
112 
113     GotNotification();
114   }
115 
116   MOCK_METHOD0(GotNotification, void());
117 
118  private:
119   base::UnsafeSharedMemoryRegion shared_memory_region_;
120   std::unique_ptr<base::CancelableSyncSocket> socket_;
121 };
122 
CreateNoDelegate(AudioOutputDelegate::EventHandler * event_handler)123 std::unique_ptr<AudioOutputDelegate> CreateNoDelegate(
124     AudioOutputDelegate::EventHandler* event_handler) {
125   return nullptr;
126 }
127 
NotCalled(mojo::PendingRemote<mojom::AudioOutputStream>,mojom::ReadWriteAudioDataPipePtr)128 void NotCalled(mojo::PendingRemote<mojom::AudioOutputStream>,
129                mojom::ReadWriteAudioDataPipePtr) {
130   ADD_FAILURE() << "The StreamCreated callback was called despite the test "
131                    "expecting it not to.";
132 }
133 
134 }  // namespace
135 
136 class MojoAudioOutputStreamTest : public Test {
137  public:
MojoAudioOutputStreamTest()138   MojoAudioOutputStreamTest()
139       : foreign_socket_(std::make_unique<TestCancelableSyncSocket>()) {}
140 
CreateAudioOutput()141   mojo::Remote<mojom::AudioOutputStream> CreateAudioOutput() {
142     mojo::Remote<mojom::AudioOutputStream> remote;
143     pending_stream_receiver = remote.BindNewPipeAndPassReceiver();
144     ExpectDelegateCreation();
145     impl_ = std::make_unique<MojoAudioOutputStream>(
146         base::BindOnce(&MockDelegateFactory::CreateDelegate,
147                        base::Unretained(&mock_delegate_factory_)),
148         base::BindOnce(&MojoAudioOutputStreamTest::CreatedStream,
149                        base::Unretained(this)),
150         base::BindOnce(&MockDeleter::Finished, base::Unretained(&deleter_)));
151     return remote;
152   }
153 
154  protected:
CreatedStream(mojo::PendingRemote<mojom::AudioOutputStream> stream,mojom::ReadWriteAudioDataPipePtr data_pipe)155   void CreatedStream(mojo::PendingRemote<mojom::AudioOutputStream> stream,
156                      mojom::ReadWriteAudioDataPipePtr data_pipe) {
157     EXPECT_EQ(mojo::FuseMessagePipes(pending_stream_receiver.PassPipe(),
158                                      stream.PassPipe()),
159               MOJO_RESULT_OK);
160     client_.Initialize(std::move(data_pipe));
161   }
162 
ExpectDelegateCreation()163   void ExpectDelegateCreation() {
164     delegate_ = new StrictMock<MockDelegate>();
165     mock_delegate_factory_.PrepareDelegateForCreation(
166         base::WrapUnique(delegate_));
167     EXPECT_TRUE(
168         base::CancelableSyncSocket::CreatePair(&local_, foreign_socket_.get()));
169     mem_ = base::UnsafeSharedMemoryRegion::Create(kShmemSize);
170     EXPECT_TRUE(mem_.IsValid());
171     EXPECT_CALL(mock_delegate_factory_, MockCreateDelegate(NotNull()))
172         .WillOnce(SaveArg<0>(&delegate_event_handler_));
173   }
174 
175   base::test::SingleThreadTaskEnvironment task_environment_;
176   base::CancelableSyncSocket local_;
177   std::unique_ptr<TestCancelableSyncSocket> foreign_socket_;
178   base::UnsafeSharedMemoryRegion mem_;
179   StrictMock<MockDelegate>* delegate_ = nullptr;
180   AudioOutputDelegate::EventHandler* delegate_event_handler_ = nullptr;
181   StrictMock<MockDelegateFactory> mock_delegate_factory_;
182   StrictMock<MockDeleter> deleter_;
183   StrictMock<MockClient> client_;
184   mojo::PendingReceiver<mojom::AudioOutputStream> pending_stream_receiver;
185   std::unique_ptr<MojoAudioOutputStream> impl_;
186 };
187 
TEST_F(MojoAudioOutputStreamTest,NoDelegate_SignalsError)188 TEST_F(MojoAudioOutputStreamTest, NoDelegate_SignalsError) {
189   MojoAudioOutputStream stream(
190       base::BindOnce(&CreateNoDelegate), base::BindOnce(&NotCalled),
191       base::BindOnce(&MockDeleter::Finished, base::Unretained(&deleter_)));
192   EXPECT_CALL(deleter_, Finished(true));
193   base::RunLoop().RunUntilIdle();
194 }
195 
TEST_F(MojoAudioOutputStreamTest,Play_Plays)196 TEST_F(MojoAudioOutputStreamTest, Play_Plays) {
197   mojo::Remote<mojom::AudioOutputStream> audio_output_remote =
198       CreateAudioOutput();
199 
200   EXPECT_CALL(client_, GotNotification());
201   EXPECT_CALL(*delegate_, OnPlayStream());
202 
203   delegate_event_handler_->OnStreamCreated(kStreamId, std::move(mem_),
204                                            std::move(foreign_socket_));
205   audio_output_remote->Play();
206   base::RunLoop().RunUntilIdle();
207 }
208 
TEST_F(MojoAudioOutputStreamTest,Pause_Pauses)209 TEST_F(MojoAudioOutputStreamTest, Pause_Pauses) {
210   mojo::Remote<mojom::AudioOutputStream> audio_output_remote =
211       CreateAudioOutput();
212 
213   EXPECT_CALL(client_, GotNotification());
214   EXPECT_CALL(*delegate_, OnPauseStream());
215 
216   delegate_event_handler_->OnStreamCreated(kStreamId, std::move(mem_),
217                                            std::move(foreign_socket_));
218   audio_output_remote->Pause();
219   base::RunLoop().RunUntilIdle();
220 }
221 
TEST_F(MojoAudioOutputStreamTest,SetVolume_SetsVolume)222 TEST_F(MojoAudioOutputStreamTest, SetVolume_SetsVolume) {
223   mojo::Remote<mojom::AudioOutputStream> audio_output_remote =
224       CreateAudioOutput();
225 
226   EXPECT_CALL(client_, GotNotification());
227   EXPECT_CALL(*delegate_, OnSetVolume(kNewVolume));
228 
229   delegate_event_handler_->OnStreamCreated(kStreamId, std::move(mem_),
230                                            std::move(foreign_socket_));
231   audio_output_remote->SetVolume(kNewVolume);
232   base::RunLoop().RunUntilIdle();
233 }
234 
TEST_F(MojoAudioOutputStreamTest,Flush_FlushesStream)235 TEST_F(MojoAudioOutputStreamTest, Flush_FlushesStream) {
236   mojo::Remote<mojom::AudioOutputStream> audio_output_remote =
237       CreateAudioOutput();
238 
239   EXPECT_CALL(client_, GotNotification());
240   EXPECT_CALL(*delegate_, OnFlushStream());
241   delegate_event_handler_->OnStreamCreated(kStreamId, std::move(mem_),
242                                            std::move(foreign_socket_));
243   audio_output_remote->Flush();
244   base::RunLoop().RunUntilIdle();
245 }
246 
TEST_F(MojoAudioOutputStreamTest,DestructWithCallPending_Safe)247 TEST_F(MojoAudioOutputStreamTest, DestructWithCallPending_Safe) {
248   mojo::Remote<mojom::AudioOutputStream> audio_output_remote =
249       CreateAudioOutput();
250   EXPECT_CALL(client_, GotNotification());
251   base::RunLoop().RunUntilIdle();
252 
253   ASSERT_NE(nullptr, delegate_event_handler_);
254   foreign_socket_->ExpectOwnershipTransfer();
255   delegate_event_handler_->OnStreamCreated(kStreamId, std::move(mem_),
256                                            std::move(foreign_socket_));
257   audio_output_remote->Play();
258   impl_.reset();
259   base::RunLoop().RunUntilIdle();
260 }
261 
TEST_F(MojoAudioOutputStreamTest,Created_NotifiesClient)262 TEST_F(MojoAudioOutputStreamTest, Created_NotifiesClient) {
263   mojo::Remote<mojom::AudioOutputStream> audio_output_remote =
264       CreateAudioOutput();
265   base::RunLoop().RunUntilIdle();
266 
267   EXPECT_CALL(client_, GotNotification());
268 
269   ASSERT_NE(nullptr, delegate_event_handler_);
270   foreign_socket_->ExpectOwnershipTransfer();
271   delegate_event_handler_->OnStreamCreated(kStreamId, std::move(mem_),
272                                            std::move(foreign_socket_));
273 
274   base::RunLoop().RunUntilIdle();
275 }
276 
TEST_F(MojoAudioOutputStreamTest,SetVolumeTooLarge_Error)277 TEST_F(MojoAudioOutputStreamTest, SetVolumeTooLarge_Error) {
278   mojo::Remote<mojom::AudioOutputStream> audio_output_remote =
279       CreateAudioOutput();
280   EXPECT_CALL(deleter_, Finished(true));
281   EXPECT_CALL(client_, GotNotification());
282 
283   delegate_event_handler_->OnStreamCreated(kStreamId, std::move(mem_),
284                                            std::move(foreign_socket_));
285   audio_output_remote->SetVolume(15);
286   base::RunLoop().RunUntilIdle();
287   Mock::VerifyAndClear(&deleter_);
288 }
289 
TEST_F(MojoAudioOutputStreamTest,SetVolumeNegative_Error)290 TEST_F(MojoAudioOutputStreamTest, SetVolumeNegative_Error) {
291   mojo::Remote<mojom::AudioOutputStream> audio_output_remote =
292       CreateAudioOutput();
293   EXPECT_CALL(deleter_, Finished(true));
294   EXPECT_CALL(client_, GotNotification());
295 
296   delegate_event_handler_->OnStreamCreated(kStreamId, std::move(mem_),
297                                            std::move(foreign_socket_));
298   audio_output_remote->SetVolume(-0.5);
299   base::RunLoop().RunUntilIdle();
300   Mock::VerifyAndClear(&deleter_);
301 }
302 
TEST_F(MojoAudioOutputStreamTest,DelegateErrorBeforeCreated_PropagatesError)303 TEST_F(MojoAudioOutputStreamTest, DelegateErrorBeforeCreated_PropagatesError) {
304   mojo::Remote<mojom::AudioOutputStream> audio_output_remote =
305       CreateAudioOutput();
306   EXPECT_CALL(deleter_, Finished(true));
307 
308   ASSERT_NE(nullptr, delegate_event_handler_);
309   delegate_event_handler_->OnStreamError(kStreamId);
310 
311   base::RunLoop().RunUntilIdle();
312   Mock::VerifyAndClear(&deleter_);
313 }
314 
TEST_F(MojoAudioOutputStreamTest,DelegateErrorAfterCreated_PropagatesError)315 TEST_F(MojoAudioOutputStreamTest, DelegateErrorAfterCreated_PropagatesError) {
316   mojo::Remote<mojom::AudioOutputStream> audio_output_remote =
317       CreateAudioOutput();
318   EXPECT_CALL(client_, GotNotification());
319   EXPECT_CALL(deleter_, Finished(true));
320   base::RunLoop().RunUntilIdle();
321 
322   ASSERT_NE(nullptr, delegate_event_handler_);
323   foreign_socket_->ExpectOwnershipTransfer();
324   delegate_event_handler_->OnStreamCreated(kStreamId, std::move(mem_),
325                                            std::move(foreign_socket_));
326   delegate_event_handler_->OnStreamError(kStreamId);
327 
328   base::RunLoop().RunUntilIdle();
329   Mock::VerifyAndClear(&deleter_);
330 }
331 
TEST_F(MojoAudioOutputStreamTest,RemoteEndGone_CallsDeleter)332 TEST_F(MojoAudioOutputStreamTest, RemoteEndGone_CallsDeleter) {
333   mojo::Remote<mojom::AudioOutputStream> audio_output_remote =
334       CreateAudioOutput();
335 
336   EXPECT_CALL(client_, GotNotification());
337   EXPECT_CALL(deleter_, Finished(false));
338 
339   delegate_event_handler_->OnStreamCreated(kStreamId, std::move(mem_),
340                                            std::move(foreign_socket_));
341   audio_output_remote.reset();
342   base::RunLoop().RunUntilIdle();
343   Mock::VerifyAndClear(&deleter_);
344 }
345 
346 }  // namespace media
347