Index: content/browser/renderer_host/media/audio_output_impl_unittest.cc |
diff --git a/content/browser/renderer_host/media/audio_output_impl_unittest.cc b/content/browser/renderer_host/media/audio_output_impl_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f8967e0c8e924dfe9cc262734e51590fc8f16dc8 |
--- /dev/null |
+++ b/content/browser/renderer_host/media/audio_output_impl_unittest.cc |
@@ -0,0 +1,347 @@ |
+// Copyright 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 "content/browser/renderer_host/media/audio_output_impl.h" |
+ |
+#include <utility> |
+ |
+#include "base/memory/shared_memory.h" |
+#include "base/message_loop/message_loop.h" |
+#include "base/run_loop.h" |
+#include "base/sync_socket.h" |
+#include "content/common/media/audio_output.mojom.h" |
+#include "media/audio/audio_output_controller.h" |
+#include "mojo/public/cpp/system/platform_handle.h" |
+#include "testing/gmock/include/gmock/gmock.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace content { |
+ |
+namespace { |
+ |
+const double kNewVolume = 0.618; |
+// Not actually used, but sent from the AudioOutputDelegate. |
+const int kStreamId = 0; |
+ |
+using testing::_; |
+using testing::Mock; |
+using testing::NotNull; |
+using testing::Return; |
+using testing::SaveArg; |
+using testing::StrictMock; |
+using testing::Test; |
+using AudioOutput = mojom::AudioOutput; |
+using AudioOutputPtr = mojo::InterfacePtr<AudioOutput>; |
+ |
+class MockDelegate : public AudioOutputDelegate { |
+ public: |
+ MOCK_CONST_METHOD0(GetController, |
+ scoped_refptr<media::AudioOutputController>()); |
+ MOCK_CONST_METHOD0(GetStreamId, int()); |
+ MOCK_METHOD0(OnPlayStream, void()); |
+ MOCK_METHOD0(OnPauseStream, void()); |
+ MOCK_METHOD1(OnSetVolume, void(double)); |
+}; |
+ |
+class MockDelegateFactory { |
+ public: |
+ void PrepareDelegateForCreation( |
+ std::unique_ptr<AudioOutputDelegate> delegate) { |
+ ASSERT_EQ(nullptr, delegate_); |
+ delegate_.swap(delegate); |
+ } |
+ |
+ std::unique_ptr<AudioOutputDelegate> CreateDelegate( |
+ AudioOutputDelegate::EventHandler* handler, |
+ const media::AudioParameters& params) { |
+ MockCreateDelegate(handler, params); |
+ EXPECT_NE(nullptr, delegate_); |
+ return std::move(delegate_); |
+ } |
+ |
+ MOCK_METHOD2(MockCreateDelegate, |
+ void(AudioOutputDelegate::EventHandler*, |
+ const media::AudioParameters&)); |
+ |
+ private: |
+ std::unique_ptr<AudioOutputDelegate> delegate_; |
+}; |
+ |
+class MockFinishedListener { |
+ public: |
+ MOCK_METHOD1(Finished, void(AudioOutput*)); |
+}; |
+ |
+class MockClient { |
+ public: |
+ MockClient() {} |
+ |
+ void Started(mojo::ScopedSharedBufferHandle shared_buffer, |
+ mojo::ScopedHandle socket_handle) { |
+ ASSERT_TRUE(shared_buffer.is_valid()); |
+ ASSERT_TRUE(socket_handle.is_valid()); |
+ |
+ base::PlatformFile fd; |
+ mojo::UnwrapPlatformFile(std::move(socket_handle), &fd); |
+ socket_ = base::MakeUnique<base::CancelableSyncSocket>(fd); |
+ EXPECT_NE(socket_->handle(), base::CancelableSyncSocket::kInvalidHandle); |
+ |
+ size_t memory_length; |
+ base::SharedMemoryHandle shmem_handle; |
+ bool read_only; |
+ EXPECT_EQ( |
+ mojo::UnwrapSharedMemoryHandle(std::move(shared_buffer), &shmem_handle, |
+ &memory_length, &read_only), |
+ MOJO_RESULT_OK); |
+ EXPECT_FALSE(read_only); |
+ buffer_ = base::MakeUnique<base::SharedMemory>(shmem_handle, read_only); |
+ |
+ GotNotification(); |
+ } |
+ |
+ MOCK_METHOD0(GotNotification, void()); |
+ |
+ private: |
+ std::unique_ptr<base::SharedMemory> buffer_; |
+ std::unique_ptr<base::CancelableSyncSocket> socket_; |
+}; |
+} // namespace |
+ |
+class AudioOutputImplTest : public Test { |
+ public: |
+ AudioOutputImplTest() |
+ : impl_(base::MakeUnique<AudioOutputImpl>( |
+ mojo::MakeRequest(&audio_output_ptr_), |
+ base::BindOnce(&MockDelegateFactory::CreateDelegate, |
+ base::Unretained(&mock_delegate_factory_)), |
+ base::BindOnce(&MockFinishedListener::Finished, |
+ base::Unretained(&listener_)))) {} |
+ |
+ void ExpectDelegateCreation() { |
+ delegate_ = new StrictMock<MockDelegate>(); |
+ mock_delegate_factory_.PrepareDelegateForCreation( |
+ base::WrapUnique(delegate_)); |
+ EXPECT_TRUE( |
+ base::CancelableSyncSocket::CreatePair(&local_, &foreign_socket_)); |
+ EXPECT_TRUE(mem_.CreateAnonymous(100)); |
+ EXPECT_CALL(mock_delegate_factory_, MockCreateDelegate(NotNull(), _)) |
+ .WillOnce(SaveArg<0>(&delegate_event_handler_)); |
+ } |
+ |
+ base::MessageLoop loop_; |
+ base::CancelableSyncSocket local_, foreign_socket_; |
+ base::SharedMemory mem_; |
+ StrictMock<MockDelegate>* delegate_ = nullptr; |
+ AudioOutputDelegate::EventHandler* delegate_event_handler_ = nullptr; |
+ StrictMock<MockDelegateFactory> mock_delegate_factory_; |
+ StrictMock<MockFinishedListener> listener_; |
+ AudioOutputPtr audio_output_ptr_; |
+ std::unique_ptr<AudioOutputImpl> impl_; |
+}; |
+ |
+TEST_F(AudioOutputImplTest, Play_Plays) { |
+ ExpectDelegateCreation(); |
+ MockClient client; |
+ audio_output_ptr_->Start( |
+ media::AudioParameters::UnavailableDeviceParams(), |
+ base::Bind(&MockClient::Started, base::Unretained(&client))); |
+ audio_output_ptr_->Play(); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ // AudioOutputImpl has to wait with playing until it has been constructed. |
+ // Same for other operations. |
+ EXPECT_CALL(*delegate_, OnPlayStream()); |
+ ASSERT_NE(nullptr, delegate_event_handler_); |
+ delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
+ base::RunLoop().RunUntilIdle(); |
+} |
+ |
+TEST_F(AudioOutputImplTest, Pause_Pauses) { |
+ ExpectDelegateCreation(); |
+ MockClient client; |
+ audio_output_ptr_->Start( |
+ media::AudioParameters::UnavailableDeviceParams(), |
+ base::Bind(&MockClient::Started, base::Unretained(&client))); |
+ audio_output_ptr_->Pause(); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ EXPECT_CALL(*delegate_, OnPauseStream()); |
+ ASSERT_NE(nullptr, delegate_event_handler_); |
+ delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
+ base::RunLoop().RunUntilIdle(); |
+} |
+ |
+TEST_F(AudioOutputImplTest, SetVolume_SetsVolume) { |
+ ExpectDelegateCreation(); |
+ MockClient client; |
+ audio_output_ptr_->Start( |
+ media::AudioParameters::UnavailableDeviceParams(), |
+ base::Bind(&MockClient::Started, base::Unretained(&client))); |
+ audio_output_ptr_->SetVolume(kNewVolume); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ EXPECT_CALL(*delegate_, OnSetVolume(kNewVolume)); |
+ ASSERT_NE(nullptr, delegate_event_handler_); |
+ delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
+ base::RunLoop().RunUntilIdle(); |
+} |
+ |
+TEST_F(AudioOutputImplTest, DestructWithCallPending_CancelsCall) { |
+ ExpectDelegateCreation(); |
+ MockClient client; |
+ audio_output_ptr_->Start( |
+ media::AudioParameters::UnavailableDeviceParams(), |
+ base::Bind(&MockClient::Started, base::Unretained(&client))); |
+ base::RunLoop().RunUntilIdle(); |
+ ASSERT_NE(nullptr, delegate_event_handler_); |
+ delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
+ audio_output_ptr_->Play(); |
+ impl_.reset(); |
+ |
+ base::RunLoop().RunUntilIdle(); |
+} |
+ |
+TEST_F(AudioOutputImplTest, Start_NotifiesClient) { |
+ ExpectDelegateCreation(); |
+ MockClient client; |
+ |
+ audio_output_ptr_->Start( |
+ media::AudioParameters::UnavailableDeviceParams(), |
+ base::Bind(&MockClient::Started, base::Unretained(&client))); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ EXPECT_CALL(client, GotNotification()); |
+ |
+ ASSERT_NE(nullptr, delegate_event_handler_); |
+ delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
+ |
+ base::RunLoop().RunUntilIdle(); |
+} |
+ |
+TEST_F(AudioOutputImplTest, PlayBeforeStart_Error) { |
+ EXPECT_CALL(listener_, Finished(impl_.get())); |
+ audio_output_ptr_->Play(); |
+ base::RunLoop().RunUntilIdle(); |
+} |
+ |
+TEST_F(AudioOutputImplTest, PauseBeforeStart_Error) { |
+ EXPECT_CALL(listener_, Finished(impl_.get())); |
+ audio_output_ptr_->Pause(); |
+ base::RunLoop().RunUntilIdle(); |
+} |
+ |
+TEST_F(AudioOutputImplTest, SetVolumeBeforeStart_Error) { |
+ EXPECT_CALL(listener_, Finished(impl_.get())); |
+ audio_output_ptr_->SetVolume(kNewVolume); |
+ base::RunLoop().RunUntilIdle(); |
+} |
+ |
+TEST_F(AudioOutputImplTest, SetVolumeTooLarge_Error) { |
+ ExpectDelegateCreation(); |
+ EXPECT_CALL(listener_, Finished(impl_.get())); |
+ MockClient client; |
+ audio_output_ptr_->Start( |
+ media::AudioParameters::UnavailableDeviceParams(), |
+ base::Bind(&MockClient::Started, base::Unretained(&client))); |
+ audio_output_ptr_->SetVolume(15); |
+ base::RunLoop().RunUntilIdle(); |
+ ASSERT_NE(nullptr, delegate_event_handler_); |
+ delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
+ |
+ base::RunLoop().RunUntilIdle(); |
+} |
+ |
+TEST_F(AudioOutputImplTest, SetVolumeNegative_Error) { |
+ ExpectDelegateCreation(); |
+ EXPECT_CALL(listener_, Finished(impl_.get())); |
+ MockClient client; |
+ audio_output_ptr_->Start( |
+ media::AudioParameters::UnavailableDeviceParams(), |
+ base::Bind(&MockClient::Started, base::Unretained(&client))); |
+ audio_output_ptr_->SetVolume(-0.5); |
+ base::RunLoop().RunUntilIdle(); |
+ ASSERT_NE(nullptr, delegate_event_handler_); |
+ delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
+ |
+ base::RunLoop().RunUntilIdle(); |
+} |
+ |
+TEST_F(AudioOutputImplTest, StartStart_Error) { |
+ MockClient client; |
+ ExpectDelegateCreation(); |
+ EXPECT_CALL(listener_, Finished(impl_.get())); |
+ audio_output_ptr_->Start( |
+ media::AudioParameters::UnavailableDeviceParams(), |
+ base::Bind(&MockClient::Started, base::Unretained(&client))); |
+ audio_output_ptr_->Start( |
+ media::AudioParameters::UnavailableDeviceParams(), |
+ base::Bind(&MockClient::Started, base::Unretained(&client))); |
+ base::RunLoop().RunUntilIdle(); |
+ ASSERT_NE(nullptr, delegate_event_handler_); |
+ delegate_event_handler_->OnStreamCreated( |
+ kStreamId, &mem_, &foreign_socket_); // Should be enough to trigger the |
+ // error, as the first Start call |
+ // will finish and the next will be |
+ // processed. |
+ base::RunLoop().RunUntilIdle(); |
+} |
+ |
+TEST_F(AudioOutputImplTest, DelegateErrorBeforeCreated_PropagatesError) { |
+ ExpectDelegateCreation(); |
+ MockClient client; |
+ EXPECT_CALL(listener_, Finished(impl_.get())); |
+ |
+ audio_output_ptr_->Start( |
+ media::AudioParameters::UnavailableDeviceParams(), |
+ base::Bind(&MockClient::Started, base::Unretained(&client))); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ ASSERT_NE(nullptr, delegate_event_handler_); |
+ delegate_event_handler_->OnStreamError(kStreamId); |
+ |
+ base::RunLoop().RunUntilIdle(); |
+} |
+ |
+TEST_F(AudioOutputImplTest, DelegateErrorAfterCreated_PropagatesError) { |
+ ExpectDelegateCreation(); |
+ MockClient client; |
+ EXPECT_CALL(listener_, Finished(impl_.get())); |
+ |
+ audio_output_ptr_->Start( |
+ media::AudioParameters::UnavailableDeviceParams(), |
+ base::Bind(&MockClient::Started, base::Unretained(&client))); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ ASSERT_NE(nullptr, delegate_event_handler_); |
+ delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
+ delegate_event_handler_->OnStreamError(kStreamId); |
+ |
+ base::RunLoop().RunUntilIdle(); |
+} |
+ |
+TEST_F(AudioOutputImplTest, RemoteEndGone_Error) { |
+ EXPECT_CALL(listener_, Finished(impl_.get())); |
+ audio_output_ptr_.reset(); |
+ base::RunLoop().RunUntilIdle(); |
+ Mock::VerifyAndClear(&listener_); |
+} |
+ |
+TEST_F(AudioOutputImplTest, |
+ RemoteEndGoneWhileWaitingForDelegateCreation_Error) { |
+ ExpectDelegateCreation(); |
+ MockClient client; |
+ EXPECT_CALL(listener_, Finished(impl_.get())); |
+ audio_output_ptr_->Start( |
+ media::AudioParameters::UnavailableDeviceParams(), |
+ base::Bind(&MockClient::Started, base::Unretained(&client))); |
+ base::RunLoop().RunUntilIdle(); |
+ audio_output_ptr_.reset(); |
+ |
+ ASSERT_NE(nullptr, delegate_event_handler_); |
+ delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
+ base::RunLoop().RunUntilIdle(); |
+ Mock::VerifyAndClear(&listener_); |
+} |
+ |
+} // namespace content |