OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2016 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 "base/bind.h" |
| 6 #include "base/memory/shared_memory.h" |
| 7 #include "base/run_loop.h" |
| 8 #include "base/sync_socket.h" |
| 9 #include "content/public/test/test_browser_thread.h" |
| 10 #include "content/renderer/media/audio_message_filter.h" |
| 11 #include "testing/gmock/include/gmock/gmock.h" |
| 12 #include "testing/gtest/include/gtest/gtest.h" |
| 13 /* |
| 14 using ::testing::_; |
| 15 |
| 16 namespace content { |
| 17 |
| 18 namespace { |
| 19 // const int kBufferSize1 = 30; |
| 20 const int kBufferSize2 = 40; |
| 21 const int kBufferSize3 = 50; |
| 22 // const int kRenderFrameId = 5; |
| 23 const int kStreamId1 = 9; |
| 24 const int kStreamId2 = 20; |
| 25 const int kStreamId3 = 3; |
| 26 } |
| 27 |
| 28 class MockAudioMessageFilter : public AudioMessageFilter { |
| 29 public: |
| 30 MockAudioMessageFilter( |
| 31 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) |
| 32 : AudioMessageFilter(io_task_runner) {} |
| 33 MOCK_METHOD4(OnStreamCreated, |
| 34 void(int stream_id, |
| 35 base::SharedMemoryHandle handle, |
| 36 base::SyncSocket::TransitDescriptor socket_descriptor, |
| 37 uint32_t length)); |
| 38 MOCK_METHOD2(OnStreamStateChanged, |
| 39 void(int stream_id, media::AudioOutputIPCDelegateState state)); |
| 40 MOCK_METHOD1(CloseStream, void(int stream_id)); |
| 41 |
| 42 protected: |
| 43 ~MockAudioMessageFilter() {} |
| 44 }; |
| 45 |
| 46 class TestAudioOutputImpl; |
| 47 |
| 48 class AudioOutputClientTest : public testing::Test { |
| 49 public: |
| 50 AudioOutputClientTest() { |
| 51 message_loop_.reset(new base::MessageLoopForUI()); |
| 52 io_thread_.reset( |
| 53 new TestBrowserThread(BrowserThread::IO, message_loop_.get())); |
| 54 |
| 55 audio_output_client_ = |
| 56 new AudioOutputClient(NULL, message_loop_->task_runner()); |
| 57 audio_message_filter_ = |
| 58 new MockAudioMessageFilter(message_loop_->task_runner()); |
| 59 } |
| 60 |
| 61 void CreateStreamCallback(int stream_id, |
| 62 media::mojom::AudioOutputStreamPtr stream, |
| 63 mojo::ScopedSharedBufferHandle shared_buffer, |
| 64 mojo::ScopedHandle socket_descriptor) {} |
| 65 static mojo::ScopedSharedBufferHandle GenerateBuffer(int buffer_size) { |
| 66 base::SharedMemory shared_memory; |
| 67 shared_memory.CreateAnonymous(buffer_size); |
| 68 base::SharedMemoryHandle shared_memory_handle = shared_memory.handle(); |
| 69 |
| 70 MojoHandle mojo_foreign_memory_handle; |
| 71 |
| 72 MojoResult shared_buffer_result = mojo::edk::CreateSharedBufferWrapper( |
| 73 shared_memory_handle, shared_memory.requested_size(), false, |
| 74 &mojo_foreign_memory_handle); |
| 75 |
| 76 EXPECT_EQ(shared_buffer_result, MOJO_RESULT_OK); |
| 77 |
| 78 mojo::ScopedSharedBufferHandle shared_buffer_handle = |
| 79 mojo::ScopedSharedBufferHandle( |
| 80 mojo::SharedBufferHandle(mojo_foreign_memory_handle)); |
| 81 return shared_buffer_handle; |
| 82 } |
| 83 |
| 84 static mojo::ScopedHandle GenerateSocket() { |
| 85 base::SyncSocket::TransitDescriptor socket_descriptor; |
| 86 |
| 87 MojoHandle socket_descriptor_handle; |
| 88 MojoResult platform_handle_result; |
| 89 |
| 90 #if defined(OS_WIN) |
| 91 platform_handle_result = mojo::edk::CreatePlatformHandleWrapper( |
| 92 mojo::edk::ScopedPlatformHandle( |
| 93 mojo::edk::PlatformHandle(socket_descriptor), |
| 94 &socket_descriptor_handle); |
| 95 #else |
| 96 platform_handle_result = mojo::edk::CreatePlatformHandleWrapper( |
| 97 mojo::edk::ScopedPlatformHandle( |
| 98 mojo::edk::PlatformHandle(socket_descriptor.fd)), |
| 99 &socket_descriptor_handle); |
| 100 #endif |
| 101 |
| 102 EXPECT_EQ(platform_handle_result, MOJO_RESULT_OK); |
| 103 |
| 104 mojo::ScopedHandle socket_handle = |
| 105 mojo::ScopedHandle(mojo::Handle(socket_descriptor_handle)); |
| 106 return socket_handle; |
| 107 } |
| 108 |
| 109 protected: |
| 110 scoped_refptr<AudioOutputClient> audio_output_client_; |
| 111 std::unique_ptr<base::MessageLoop> message_loop_; |
| 112 scoped_refptr<MockAudioMessageFilter> audio_message_filter_; |
| 113 std::unique_ptr<TestAudioOutputImpl> audio_output_impl_; |
| 114 |
| 115 private: |
| 116 std::unique_ptr<TestBrowserThread> io_thread_; |
| 117 DISALLOW_COPY_AND_ASSIGN(AudioOutputClientTest); |
| 118 }; |
| 119 |
| 120 class TestAudioOutputStreamImpl : public media::mojom::AudioOutputStream { |
| 121 public: |
| 122 TestAudioOutputStreamImpl(media::mojom::AudioOutputStreamRequest request) |
| 123 : binding_(this, std::move(request)) {} |
| 124 ~TestAudioOutputStreamImpl() override {} |
| 125 |
| 126 // AudioOutputStream implementation: |
| 127 static base::RunLoop* run_loop_; |
| 128 static int stream_count_; |
| 129 void Close() override { |
| 130 stream_count_--; |
| 131 // The number of streams that will be closed is 2. |
| 132 EXPECT_TRUE(stream_count_ > -1); |
| 133 if (stream_count_ == 0) |
| 134 run_loop_->Quit(); |
| 135 } |
| 136 |
| 137 private: |
| 138 mojo::Binding<media::mojom::AudioOutputStream> binding_; |
| 139 }; |
| 140 |
| 141 class TestAudioOutputImpl : public media::mojom::AudioOutput { |
| 142 public: |
| 143 TestAudioOutputImpl(media::mojom::AudioOutputRequest request) |
| 144 : binding_(this, std::move(request)) {} |
| 145 ~TestAudioOutputImpl() override {} |
| 146 |
| 147 // AudioOutput implementation: |
| 148 void CreateStream(int stream_id, |
| 149 const media::AudioParameters& params, |
| 150 const CreateStreamCallback& callback) override { |
| 151 media::mojom::AudioOutputStreamPtr stream_ptr = |
| 152 media::mojom::AudioOutputStreamPtr(); |
| 153 std::unique_ptr<TestAudioOutputStreamImpl> stream( |
| 154 new TestAudioOutputStreamImpl(mojo::GetProxy(&stream_ptr))); |
| 155 mojo::ScopedSharedBufferHandle shared_buffer_handle = |
| 156 mojo::ScopedSharedBufferHandle(mojo::SharedBufferHandle()); |
| 157 |
| 158 callback.Run(stream_id, std::move(stream_ptr), |
| 159 std::move(shared_buffer_handle), |
| 160 AudioOutputClientTest::GenerateSocket()); |
| 161 } |
| 162 |
| 163 private: |
| 164 mojo::Binding<media::mojom::AudioOutput> binding_; |
| 165 }; |
| 166 |
| 167 base::RunLoop* TestAudioOutputStreamImpl::run_loop_; |
| 168 int TestAudioOutputStreamImpl::stream_count_ = 2; |
| 169 |
| 170 TEST_F(AudioOutputClientTest, CreateStream) { |
| 171 base::RunLoop run_loop; |
| 172 media::mojom::AudioOutputPtr audio_output_impl_ptr; |
| 173 audio_output_impl_.reset( |
| 174 new TestAudioOutputImpl(mojo::GetProxy(&audio_output_impl_ptr))); |
| 175 media::AudioParameters params( |
| 176 media::AudioParameters::AUDIO_FAKE, media::CHANNEL_LAYOUT_STEREO, |
| 177 media::AudioParameters::kAudioCDSampleRate, 16, |
| 178 media::AudioParameters::kAudioCDSampleRate / 10); |
| 179 int stream_count = 2; |
| 180 audio_output_client_->service_ = std::move(audio_output_impl_ptr); |
| 181 |
| 182 audio_output_client_->CreateStream( |
| 183 kStreamId1, params, |
| 184 [&run_loop, &stream_count](int stream_id, |
| 185 media::mojom::AudioOutputStreamPtr stream_ptr, |
| 186 mojo::ScopedSharedBufferHandle shared_buffer, |
| 187 mojo::ScopedHandle socket_descriptor) { |
| 188 EXPECT_EQ(kStreamId1, stream_id); |
| 189 EXPECT_TRUE(stream_ptr.is_bound()); |
| 190 stream_count--; |
| 191 // The number of streams that will be closed is 2. |
| 192 EXPECT_TRUE(stream_count > -1); |
| 193 if (stream_count == 1) |
| 194 run_loop.Quit(); |
| 195 }); |
| 196 |
| 197 audio_output_client_->CreateStream( |
| 198 kStreamId2, params, |
| 199 [&run_loop, &stream_count](int stream_id, |
| 200 media::mojom::AudioOutputStreamPtr stream_ptr, |
| 201 mojo::ScopedSharedBufferHandle shared_buffer, |
| 202 mojo::ScopedHandle socket_descriptor) { |
| 203 EXPECT_EQ(kStreamId2, stream_id); |
| 204 EXPECT_TRUE(stream_ptr.is_bound()); |
| 205 stream_count--; |
| 206 // The number of streams that will be closed is 2. |
| 207 EXPECT_TRUE(stream_count > -1); |
| 208 if (stream_count == 0) |
| 209 run_loop.Quit(); |
| 210 }); |
| 211 run_loop.Run(); |
| 212 } |
| 213 |
| 214 TEST_F(AudioOutputClientTest, CreateStreamCallback) { |
| 215 EXPECT_CALL(*audio_message_filter_, |
| 216 OnStreamStateChanged( |
| 217 kStreamId2, media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR)) |
| 218 .Times(0); |
| 219 EXPECT_CALL(*audio_message_filter_, |
| 220 OnStreamCreated(kStreamId2, _, _, kBufferSize2)) |
| 221 .Times(1); |
| 222 |
| 223 media::mojom::AudioOutputStreamPtr stream_ptr2; |
| 224 std::unique_ptr<TestAudioOutputStreamImpl> stream2( |
| 225 new TestAudioOutputStreamImpl(mojo::GetProxy(&stream_ptr2))); |
| 226 |
| 227 audio_output_client_->CreateStreamCallback(kStreamId2, std::move(stream_ptr2), |
| 228 GenerateBuffer(kBufferSize2), |
| 229 GenerateSocket()); |
| 230 |
| 231 EXPECT_CALL(*audio_message_filter_, |
| 232 OnStreamStateChanged( |
| 233 kStreamId3, media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR)) |
| 234 .Times(0); |
| 235 EXPECT_CALL(*audio_message_filter_, |
| 236 OnStreamCreated(kStreamId3, _, _, kBufferSize3)) |
| 237 .Times(1); |
| 238 media::mojom::AudioOutputStreamPtr stream_ptr3; |
| 239 |
| 240 std::unique_ptr<TestAudioOutputStreamImpl> stream3( |
| 241 new TestAudioOutputStreamImpl(mojo::GetProxy(&stream_ptr3))); |
| 242 |
| 243 audio_output_client_->CreateStreamCallback(kStreamId3, std::move(stream_ptr3), |
| 244 GenerateBuffer(kBufferSize3), |
| 245 GenerateSocket()); |
| 246 |
| 247 message_loop_->RunUntilIdle(); |
| 248 } |
| 249 |
| 250 TEST_F(AudioOutputClientTest, CreateStreamCallbackNotFound) { |
| 251 media::mojom::AudioOutputStreamPtr stream_ptr1; |
| 252 EXPECT_CALL(*audio_message_filter_, |
| 253 OnStreamStateChanged( |
| 254 kStreamId1, media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR)) |
| 255 .Times(0); |
| 256 EXPECT_CALL(*audio_message_filter_, |
| 257 OnStreamStateChanged( |
| 258 kStreamId1, media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR)) |
| 259 .Times(1); |
| 260 |
| 261 audio_output_client_->CreateStreamCallback(kStreamId1, std::move(stream_ptr1), |
| 262 GenerateBuffer(kBufferSize1), |
| 263 GenerateSocket()); |
| 264 |
| 265 EXPECT_CALL(*audio_message_filter_, |
| 266 OnStreamStateChanged( |
| 267 kStreamId2, media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR)) |
| 268 .Times(0); |
| 269 EXPECT_CALL(*audio_message_filter_, |
| 270 OnStreamCreated(kStreamId2, _, _, kBufferSize2)) |
| 271 .Times(1); |
| 272 |
| 273 media::mojom::AudioOutputStreamPtr stream_ptr2; |
| 274 std::unique_ptr<AudioOutputStreamImpl> stream2(new AudioOutputStreamImpl( |
| 275 mojo::GetProxy(&stream_ptr2), kStreamId2, kRenderFrameId, NULL)); |
| 276 |
| 277 audio_output_client_->CreateStreamCallback(kStreamId2, std::move(stream_ptr2), |
| 278 GenerateBuffer(kBufferSize2), |
| 279 GenerateSocket()); |
| 280 |
| 281 EXPECT_CALL(*audio_message_filter_, |
| 282 OnStreamStateChanged( |
| 283 kStreamId3, media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR)) |
| 284 .Times(0); |
| 285 EXPECT_CALL(*audio_message_filter_, |
| 286 OnStreamCreated(kStreamId3, _, _, kBufferSize3)) |
| 287 .Times(1); |
| 288 media::mojom::AudioOutputStreamPtr stream_ptr3; |
| 289 |
| 290 std::unique_ptr<AudioOutputStreamImpl> stream3(new AudioOutputStreamImpl( |
| 291 mojo::GetProxy(&stream_ptr3), kStreamId3, kRenderFrameId, NULL)); |
| 292 |
| 293 audio_output_client_->CreateStreamCallback(kStreamId3, std::move(stream_ptr3), |
| 294 GenerateBuffer(kBufferSize3), |
| 295 GenerateSocket()); |
| 296 |
| 297 message_loop_->RunUntilIdle(); |
| 298 } |
| 299 |
| 300 TEST_F(AudioOutputClientTest, CloseAuthorizedNotCreatedStream) { |
| 301 base::RunLoop run_loop; |
| 302 media::mojom::AudioOutputPtr audio_output_impl_ptr; |
| 303 audio_output_impl_.reset( |
| 304 new TestAudioOutputImpl(mojo::GetProxy(&audio_output_impl_ptr))); |
| 305 audio_output_client_->service_ = std::move(audio_output_impl_ptr); |
| 306 |
| 307 EXPECT_CALL(*audio_message_filter_, CloseStream(kStreamId1)).Times(1); |
| 308 |
| 309 audio_output_client_->CloseStream(kStreamId1); |
| 310 |
| 311 EXPECT_CALL(*audio_message_filter_, CloseStream(kStreamId2)).Times(1); |
| 312 audio_output_client_->CloseStream(kStreamId2); |
| 313 } |
| 314 |
| 315 TEST_F(AudioOutputClientTest, CloseCreatedStream) { |
| 316 TestAudioOutputStreamImpl::run_loop_ = new base::RunLoop(); |
| 317 media::mojom::AudioOutputPtr audio_output_impl_ptr; |
| 318 audio_output_impl_.reset( |
| 319 new TestAudioOutputImpl(mojo::GetProxy(&audio_output_impl_ptr))); |
| 320 audio_output_client_->service_ = std::move(audio_output_impl_ptr); |
| 321 |
| 322 media::mojom::AudioOutputStreamPtr stream_ptr1; |
| 323 std::unique_ptr<TestAudioOutputStreamImpl> stream1( |
| 324 new TestAudioOutputStreamImpl(mojo::GetProxy(&stream_ptr1))); |
| 325 audio_output_client_->streams_.insert( |
| 326 std::make_pair(kStreamId1, std::move(stream_ptr1))); |
| 327 |
| 328 // Closing an authorized but ńot created stream should call |
| 329 // AudioMessageFilter::CloseStream. |
| 330 EXPECT_CALL(*audio_message_filter_, CloseStream(kStreamId3)).Times(1); |
| 331 |
| 332 audio_output_client_->CloseStream(kStreamId3); |
| 333 |
| 334 audio_output_client_->CloseStream(kStreamId1); |
| 335 |
| 336 media::mojom::AudioOutputStreamPtr stream_ptr2; |
| 337 std::unique_ptr<TestAudioOutputStreamImpl> stream2( |
| 338 new TestAudioOutputStreamImpl(mojo::GetProxy(&stream_ptr2))); |
| 339 audio_output_client_->streams_.insert( |
| 340 std::make_pair(kStreamId2, std::move(stream_ptr2))); |
| 341 audio_output_client_->CloseStream(kStreamId2); |
| 342 TestAudioOutputStreamImpl::run_loop_->Run(); |
| 343 |
| 344 // |kStreamId1| is cllosed now. Closing it will call |
| 345 // AudioMessageFilter::CloseStream. The same for |kStreamId2| |
| 346 EXPECT_CALL(*audio_message_filter_, CloseStream(kStreamId1)).Times(1); |
| 347 audio_output_client_->CloseStream(kStreamId1); |
| 348 |
| 349 EXPECT_CALL(*audio_message_filter_, CloseStream(kStreamId2)).Times(1); |
| 350 audio_output_client_->CloseStream(kStreamId2); |
| 351 } |
| 352 |
| 353 } // namespace content |
| 354 */ |
OLD | NEW |