| 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
|
| +*/
|
|
|