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