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