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