Index: content/renderer/media/audio_output_client_unittest.cc |
diff --git a/content/renderer/media/audio_output_client_unittest.cc b/content/renderer/media/audio_output_client_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..384763e65a9880239b151510c31439f3ac26e09d |
--- /dev/null |
+++ b/content/renderer/media/audio_output_client_unittest.cc |
@@ -0,0 +1,354 @@ |
+// Copyright (c) 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "base/bind.h" |
+#include "base/memory/shared_memory.h" |
+#include "base/run_loop.h" |
+#include "base/sync_socket.h" |
+#include "content/public/test/test_browser_thread.h" |
+#include "content/renderer/media/audio_message_filter.h" |
+#include "testing/gmock/include/gmock/gmock.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+/* |
+using ::testing::_; |
+ |
+namespace content { |
+ |
+namespace { |
+// const int kBufferSize1 = 30; |
+const int kBufferSize2 = 40; |
+const int kBufferSize3 = 50; |
+// const int kRenderFrameId = 5; |
+const int kStreamId1 = 9; |
+const int kStreamId2 = 20; |
+const int kStreamId3 = 3; |
+} |
+ |
+class MockAudioMessageFilter : public AudioMessageFilter { |
+ public: |
+ MockAudioMessageFilter( |
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) |
+ : AudioMessageFilter(io_task_runner) {} |
+ MOCK_METHOD4(OnStreamCreated, |
+ void(int stream_id, |
+ base::SharedMemoryHandle handle, |
+ base::SyncSocket::TransitDescriptor socket_descriptor, |
+ uint32_t length)); |
+ MOCK_METHOD2(OnStreamStateChanged, |
+ void(int stream_id, media::AudioOutputIPCDelegateState state)); |
+ MOCK_METHOD1(CloseStream, void(int stream_id)); |
+ |
+ protected: |
+ ~MockAudioMessageFilter() {} |
+}; |
+ |
+class TestAudioOutputImpl; |
+ |
+class AudioOutputClientTest : public testing::Test { |
+ public: |
+ AudioOutputClientTest() { |
+ message_loop_.reset(new base::MessageLoopForUI()); |
+ io_thread_.reset( |
+ new TestBrowserThread(BrowserThread::IO, message_loop_.get())); |
+ |
+ audio_output_client_ = |
+ new AudioOutputClient(NULL, message_loop_->task_runner()); |
+ audio_message_filter_ = |
+ new MockAudioMessageFilter(message_loop_->task_runner()); |
+ } |
+ |
+ void CreateStreamCallback(int stream_id, |
+ media::mojom::AudioOutputStreamPtr stream, |
+ mojo::ScopedSharedBufferHandle shared_buffer, |
+ mojo::ScopedHandle socket_descriptor) {} |
+ static mojo::ScopedSharedBufferHandle GenerateBuffer(int buffer_size) { |
+ base::SharedMemory shared_memory; |
+ shared_memory.CreateAnonymous(buffer_size); |
+ base::SharedMemoryHandle shared_memory_handle = shared_memory.handle(); |
+ |
+ MojoHandle mojo_foreign_memory_handle; |
+ |
+ MojoResult shared_buffer_result = mojo::edk::CreateSharedBufferWrapper( |
+ shared_memory_handle, shared_memory.requested_size(), false, |
+ &mojo_foreign_memory_handle); |
+ |
+ EXPECT_EQ(shared_buffer_result, MOJO_RESULT_OK); |
+ |
+ mojo::ScopedSharedBufferHandle shared_buffer_handle = |
+ mojo::ScopedSharedBufferHandle( |
+ mojo::SharedBufferHandle(mojo_foreign_memory_handle)); |
+ return shared_buffer_handle; |
+ } |
+ |
+ static mojo::ScopedHandle GenerateSocket() { |
+ base::SyncSocket::TransitDescriptor socket_descriptor; |
+ |
+ MojoHandle socket_descriptor_handle; |
+ MojoResult platform_handle_result; |
+ |
+#if defined(OS_WIN) |
+ platform_handle_result = mojo::edk::CreatePlatformHandleWrapper( |
+ mojo::edk::ScopedPlatformHandle( |
+ mojo::edk::PlatformHandle(socket_descriptor), |
+ &socket_descriptor_handle); |
+#else |
+ platform_handle_result = mojo::edk::CreatePlatformHandleWrapper( |
+ mojo::edk::ScopedPlatformHandle( |
+ mojo::edk::PlatformHandle(socket_descriptor.fd)), |
+ &socket_descriptor_handle); |
+#endif |
+ |
+ EXPECT_EQ(platform_handle_result, MOJO_RESULT_OK); |
+ |
+ mojo::ScopedHandle socket_handle = |
+ mojo::ScopedHandle(mojo::Handle(socket_descriptor_handle)); |
+ return socket_handle; |
+ } |
+ |
+ protected: |
+ scoped_refptr<AudioOutputClient> audio_output_client_; |
+ std::unique_ptr<base::MessageLoop> message_loop_; |
+ scoped_refptr<MockAudioMessageFilter> audio_message_filter_; |
+ std::unique_ptr<TestAudioOutputImpl> audio_output_impl_; |
+ |
+ private: |
+ std::unique_ptr<TestBrowserThread> io_thread_; |
+ DISALLOW_COPY_AND_ASSIGN(AudioOutputClientTest); |
+}; |
+ |
+class TestAudioOutputStreamImpl : public media::mojom::AudioOutputStream { |
+ public: |
+ TestAudioOutputStreamImpl(media::mojom::AudioOutputStreamRequest request) |
+ : binding_(this, std::move(request)) {} |
+ ~TestAudioOutputStreamImpl() override {} |
+ |
+ // AudioOutputStream implementation: |
+ static base::RunLoop* run_loop_; |
+ static int stream_count_; |
+ void Close() override { |
+ stream_count_--; |
+ // The number of streams that will be closed is 2. |
+ EXPECT_TRUE(stream_count_ > -1); |
+ if (stream_count_ == 0) |
+ run_loop_->Quit(); |
+ } |
+ |
+ private: |
+ mojo::Binding<media::mojom::AudioOutputStream> binding_; |
+}; |
+ |
+class TestAudioOutputImpl : public media::mojom::AudioOutput { |
+ public: |
+ TestAudioOutputImpl(media::mojom::AudioOutputRequest request) |
+ : binding_(this, std::move(request)) {} |
+ ~TestAudioOutputImpl() override {} |
+ |
+ // AudioOutput implementation: |
+ void CreateStream(int stream_id, |
+ const media::AudioParameters& params, |
+ const CreateStreamCallback& callback) override { |
+ media::mojom::AudioOutputStreamPtr stream_ptr = |
+ media::mojom::AudioOutputStreamPtr(); |
+ std::unique_ptr<TestAudioOutputStreamImpl> stream( |
+ new TestAudioOutputStreamImpl(mojo::GetProxy(&stream_ptr))); |
+ mojo::ScopedSharedBufferHandle shared_buffer_handle = |
+ mojo::ScopedSharedBufferHandle(mojo::SharedBufferHandle()); |
+ |
+ callback.Run(stream_id, std::move(stream_ptr), |
+ std::move(shared_buffer_handle), |
+ AudioOutputClientTest::GenerateSocket()); |
+ } |
+ |
+ private: |
+ mojo::Binding<media::mojom::AudioOutput> binding_; |
+}; |
+ |
+base::RunLoop* TestAudioOutputStreamImpl::run_loop_; |
+int TestAudioOutputStreamImpl::stream_count_ = 2; |
+ |
+TEST_F(AudioOutputClientTest, CreateStream) { |
+ base::RunLoop run_loop; |
+ media::mojom::AudioOutputPtr audio_output_impl_ptr; |
+ audio_output_impl_.reset( |
+ new TestAudioOutputImpl(mojo::GetProxy(&audio_output_impl_ptr))); |
+ media::AudioParameters params( |
+ media::AudioParameters::AUDIO_FAKE, media::CHANNEL_LAYOUT_STEREO, |
+ media::AudioParameters::kAudioCDSampleRate, 16, |
+ media::AudioParameters::kAudioCDSampleRate / 10); |
+ int stream_count = 2; |
+ audio_output_client_->service_ = std::move(audio_output_impl_ptr); |
+ |
+ audio_output_client_->CreateStream( |
+ kStreamId1, params, |
+ [&run_loop, &stream_count](int stream_id, |
+ media::mojom::AudioOutputStreamPtr stream_ptr, |
+ mojo::ScopedSharedBufferHandle shared_buffer, |
+ mojo::ScopedHandle socket_descriptor) { |
+ EXPECT_EQ(kStreamId1, stream_id); |
+ EXPECT_TRUE(stream_ptr.is_bound()); |
+ stream_count--; |
+ // The number of streams that will be closed is 2. |
+ EXPECT_TRUE(stream_count > -1); |
+ if (stream_count == 1) |
+ run_loop.Quit(); |
+ }); |
+ |
+ audio_output_client_->CreateStream( |
+ kStreamId2, params, |
+ [&run_loop, &stream_count](int stream_id, |
+ media::mojom::AudioOutputStreamPtr stream_ptr, |
+ mojo::ScopedSharedBufferHandle shared_buffer, |
+ mojo::ScopedHandle socket_descriptor) { |
+ EXPECT_EQ(kStreamId2, stream_id); |
+ EXPECT_TRUE(stream_ptr.is_bound()); |
+ stream_count--; |
+ // The number of streams that will be closed is 2. |
+ EXPECT_TRUE(stream_count > -1); |
+ if (stream_count == 0) |
+ run_loop.Quit(); |
+ }); |
+ run_loop.Run(); |
+} |
+ |
+TEST_F(AudioOutputClientTest, CreateStreamCallback) { |
+ EXPECT_CALL(*audio_message_filter_, |
+ OnStreamStateChanged( |
+ kStreamId2, media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR)) |
+ .Times(0); |
+ EXPECT_CALL(*audio_message_filter_, |
+ OnStreamCreated(kStreamId2, _, _, kBufferSize2)) |
+ .Times(1); |
+ |
+ media::mojom::AudioOutputStreamPtr stream_ptr2; |
+ std::unique_ptr<TestAudioOutputStreamImpl> stream2( |
+ new TestAudioOutputStreamImpl(mojo::GetProxy(&stream_ptr2))); |
+ |
+ audio_output_client_->CreateStreamCallback(kStreamId2, std::move(stream_ptr2), |
+ GenerateBuffer(kBufferSize2), |
+ GenerateSocket()); |
+ |
+ EXPECT_CALL(*audio_message_filter_, |
+ OnStreamStateChanged( |
+ kStreamId3, media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR)) |
+ .Times(0); |
+ EXPECT_CALL(*audio_message_filter_, |
+ OnStreamCreated(kStreamId3, _, _, kBufferSize3)) |
+ .Times(1); |
+ media::mojom::AudioOutputStreamPtr stream_ptr3; |
+ |
+ std::unique_ptr<TestAudioOutputStreamImpl> stream3( |
+ new TestAudioOutputStreamImpl(mojo::GetProxy(&stream_ptr3))); |
+ |
+ audio_output_client_->CreateStreamCallback(kStreamId3, std::move(stream_ptr3), |
+ GenerateBuffer(kBufferSize3), |
+ GenerateSocket()); |
+ |
+ message_loop_->RunUntilIdle(); |
+} |
+ |
+TEST_F(AudioOutputClientTest, CreateStreamCallbackNotFound) { |
+ media::mojom::AudioOutputStreamPtr stream_ptr1; |
+ EXPECT_CALL(*audio_message_filter_, |
+ OnStreamStateChanged( |
+ kStreamId1, media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR)) |
+ .Times(0); |
+ EXPECT_CALL(*audio_message_filter_, |
+ OnStreamStateChanged( |
+ kStreamId1, media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR)) |
+ .Times(1); |
+ |
+ audio_output_client_->CreateStreamCallback(kStreamId1, std::move(stream_ptr1), |
+ GenerateBuffer(kBufferSize1), |
+ GenerateSocket()); |
+ |
+ EXPECT_CALL(*audio_message_filter_, |
+ OnStreamStateChanged( |
+ kStreamId2, media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR)) |
+ .Times(0); |
+ EXPECT_CALL(*audio_message_filter_, |
+ OnStreamCreated(kStreamId2, _, _, kBufferSize2)) |
+ .Times(1); |
+ |
+ media::mojom::AudioOutputStreamPtr stream_ptr2; |
+ std::unique_ptr<AudioOutputStreamImpl> stream2(new AudioOutputStreamImpl( |
+ mojo::GetProxy(&stream_ptr2), kStreamId2, kRenderFrameId, NULL)); |
+ |
+ audio_output_client_->CreateStreamCallback(kStreamId2, std::move(stream_ptr2), |
+ GenerateBuffer(kBufferSize2), |
+ GenerateSocket()); |
+ |
+ EXPECT_CALL(*audio_message_filter_, |
+ OnStreamStateChanged( |
+ kStreamId3, media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR)) |
+ .Times(0); |
+ EXPECT_CALL(*audio_message_filter_, |
+ OnStreamCreated(kStreamId3, _, _, kBufferSize3)) |
+ .Times(1); |
+ media::mojom::AudioOutputStreamPtr stream_ptr3; |
+ |
+ std::unique_ptr<AudioOutputStreamImpl> stream3(new AudioOutputStreamImpl( |
+ mojo::GetProxy(&stream_ptr3), kStreamId3, kRenderFrameId, NULL)); |
+ |
+ audio_output_client_->CreateStreamCallback(kStreamId3, std::move(stream_ptr3), |
+ GenerateBuffer(kBufferSize3), |
+ GenerateSocket()); |
+ |
+ message_loop_->RunUntilIdle(); |
+} |
+ |
+TEST_F(AudioOutputClientTest, CloseAuthorizedNotCreatedStream) { |
+ base::RunLoop run_loop; |
+ media::mojom::AudioOutputPtr audio_output_impl_ptr; |
+ audio_output_impl_.reset( |
+ new TestAudioOutputImpl(mojo::GetProxy(&audio_output_impl_ptr))); |
+ audio_output_client_->service_ = std::move(audio_output_impl_ptr); |
+ |
+ EXPECT_CALL(*audio_message_filter_, CloseStream(kStreamId1)).Times(1); |
+ |
+ audio_output_client_->CloseStream(kStreamId1); |
+ |
+ EXPECT_CALL(*audio_message_filter_, CloseStream(kStreamId2)).Times(1); |
+ audio_output_client_->CloseStream(kStreamId2); |
+} |
+ |
+TEST_F(AudioOutputClientTest, CloseCreatedStream) { |
+ TestAudioOutputStreamImpl::run_loop_ = new base::RunLoop(); |
+ media::mojom::AudioOutputPtr audio_output_impl_ptr; |
+ audio_output_impl_.reset( |
+ new TestAudioOutputImpl(mojo::GetProxy(&audio_output_impl_ptr))); |
+ audio_output_client_->service_ = std::move(audio_output_impl_ptr); |
+ |
+ media::mojom::AudioOutputStreamPtr stream_ptr1; |
+ std::unique_ptr<TestAudioOutputStreamImpl> stream1( |
+ new TestAudioOutputStreamImpl(mojo::GetProxy(&stream_ptr1))); |
+ audio_output_client_->streams_.insert( |
+ std::make_pair(kStreamId1, std::move(stream_ptr1))); |
+ |
+ // Closing an authorized but ńot created stream should call |
+ // AudioMessageFilter::CloseStream. |
+ EXPECT_CALL(*audio_message_filter_, CloseStream(kStreamId3)).Times(1); |
+ |
+ audio_output_client_->CloseStream(kStreamId3); |
+ |
+ audio_output_client_->CloseStream(kStreamId1); |
+ |
+ media::mojom::AudioOutputStreamPtr stream_ptr2; |
+ std::unique_ptr<TestAudioOutputStreamImpl> stream2( |
+ new TestAudioOutputStreamImpl(mojo::GetProxy(&stream_ptr2))); |
+ audio_output_client_->streams_.insert( |
+ std::make_pair(kStreamId2, std::move(stream_ptr2))); |
+ audio_output_client_->CloseStream(kStreamId2); |
+ TestAudioOutputStreamImpl::run_loop_->Run(); |
+ |
+ // |kStreamId1| is cllosed now. Closing it will call |
+ // AudioMessageFilter::CloseStream. The same for |kStreamId2| |
+ EXPECT_CALL(*audio_message_filter_, CloseStream(kStreamId1)).Times(1); |
+ audio_output_client_->CloseStream(kStreamId1); |
+ |
+ EXPECT_CALL(*audio_message_filter_, CloseStream(kStreamId2)).Times(1); |
+ audio_output_client_->CloseStream(kStreamId2); |
+} |
+ |
+} // namespace content |
+*/ |