OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 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 "media/mojo/services/mojo_audio_output_stream.h" |
| 6 |
| 7 #include <utility> |
| 8 |
| 9 #include "base/memory/shared_memory.h" |
| 10 #include "base/message_loop/message_loop.h" |
| 11 #include "base/run_loop.h" |
| 12 #include "base/sync_socket.h" |
| 13 #include "media/audio/audio_output_controller.h" |
| 14 #include "media/mojo/interfaces/audio_output_stream.mojom.h" |
| 15 #include "mojo/public/cpp/system/platform_handle.h" |
| 16 #include "testing/gmock/include/gmock/gmock.h" |
| 17 #include "testing/gtest/include/gtest/gtest.h" |
| 18 |
| 19 namespace media { |
| 20 |
| 21 namespace { |
| 22 |
| 23 const double kNewVolume = 0.618; |
| 24 // Not actually used, but sent from the AudioOutputDelegate. |
| 25 const int kStreamId = 0; |
| 26 const int kShmemSize = 100; |
| 27 |
| 28 using testing::_; |
| 29 using testing::Mock; |
| 30 using testing::NotNull; |
| 31 using testing::Return; |
| 32 using testing::SaveArg; |
| 33 using testing::StrictMock; |
| 34 using testing::Test; |
| 35 using AudioOutputStream = mojom::AudioOutputStream; |
| 36 using AudioOutputStreamPtr = mojo::InterfacePtr<AudioOutputStream>; |
| 37 |
| 38 class MockDelegate : NON_EXPORTED_BASE(public AudioOutputDelegate) { |
| 39 public: |
| 40 MockDelegate() {} |
| 41 ~MockDelegate() {} |
| 42 |
| 43 MOCK_CONST_METHOD0(GetController, scoped_refptr<AudioOutputController>()); |
| 44 MOCK_CONST_METHOD0(GetStreamId, int()); |
| 45 MOCK_METHOD0(OnPlayStream, void()); |
| 46 MOCK_METHOD0(OnPauseStream, void()); |
| 47 MOCK_METHOD1(OnSetVolume, void(double)); |
| 48 }; |
| 49 |
| 50 class MockDelegateFactory { |
| 51 public: |
| 52 void PrepareDelegateForCreation( |
| 53 std::unique_ptr<AudioOutputDelegate> delegate) { |
| 54 ASSERT_EQ(nullptr, delegate_); |
| 55 delegate_.swap(delegate); |
| 56 } |
| 57 |
| 58 std::unique_ptr<AudioOutputDelegate> CreateDelegate( |
| 59 AudioOutputDelegate::EventHandler* handler) { |
| 60 MockCreateDelegate(handler); |
| 61 EXPECT_NE(nullptr, delegate_); |
| 62 return std::move(delegate_); |
| 63 } |
| 64 |
| 65 MOCK_METHOD1(MockCreateDelegate, void(AudioOutputDelegate::EventHandler*)); |
| 66 |
| 67 private: |
| 68 std::unique_ptr<AudioOutputDelegate> delegate_; |
| 69 }; |
| 70 |
| 71 class MockDeleter { |
| 72 public: |
| 73 MOCK_METHOD0(Finished, void()); |
| 74 }; |
| 75 |
| 76 class MockClient { |
| 77 public: |
| 78 MockClient() {} |
| 79 |
| 80 void Initialized(mojo::ScopedSharedBufferHandle shared_buffer, |
| 81 mojo::ScopedHandle socket_handle) { |
| 82 ASSERT_TRUE(shared_buffer.is_valid()); |
| 83 ASSERT_TRUE(socket_handle.is_valid()); |
| 84 |
| 85 base::PlatformFile fd; |
| 86 mojo::UnwrapPlatformFile(std::move(socket_handle), &fd); |
| 87 socket_ = base::MakeUnique<base::CancelableSyncSocket>(fd); |
| 88 EXPECT_NE(socket_->handle(), base::CancelableSyncSocket::kInvalidHandle); |
| 89 |
| 90 size_t memory_length; |
| 91 base::SharedMemoryHandle shmem_handle; |
| 92 bool read_only; |
| 93 EXPECT_EQ( |
| 94 mojo::UnwrapSharedMemoryHandle(std::move(shared_buffer), &shmem_handle, |
| 95 &memory_length, &read_only), |
| 96 MOJO_RESULT_OK); |
| 97 EXPECT_FALSE(read_only); |
| 98 buffer_ = base::MakeUnique<base::SharedMemory>(shmem_handle, read_only); |
| 99 |
| 100 GotNotification(); |
| 101 } |
| 102 |
| 103 MOCK_METHOD0(GotNotification, void()); |
| 104 |
| 105 private: |
| 106 std::unique_ptr<base::SharedMemory> buffer_; |
| 107 std::unique_ptr<base::CancelableSyncSocket> socket_; |
| 108 }; |
| 109 |
| 110 } // namespace |
| 111 |
| 112 class MojoAudioOutputStreamTest : public Test { |
| 113 public: |
| 114 MojoAudioOutputStreamTest() {} |
| 115 |
| 116 AudioOutputStreamPtr CreateAudioOutput() { |
| 117 AudioOutputStreamPtr p; |
| 118 ExpectDelegateCreation(); |
| 119 impl_ = base::MakeUnique<MojoAudioOutputStream>( |
| 120 mojo::MakeRequest(&p), |
| 121 base::BindOnce(&MockDelegateFactory::CreateDelegate, |
| 122 base::Unretained(&mock_delegate_factory_)), |
| 123 base::Bind(&MockClient::Initialized, base::Unretained(&client_)), |
| 124 base::BindOnce(&MockDeleter::Finished, base::Unretained(&deleter_))); |
| 125 EXPECT_NE(nullptr, p); |
| 126 return p; |
| 127 } |
| 128 |
| 129 protected: |
| 130 void ExpectDelegateCreation() { |
| 131 delegate_ = new StrictMock<MockDelegate>(); |
| 132 mock_delegate_factory_.PrepareDelegateForCreation( |
| 133 base::WrapUnique(delegate_)); |
| 134 EXPECT_TRUE( |
| 135 base::CancelableSyncSocket::CreatePair(&local_, &foreign_socket_)); |
| 136 EXPECT_TRUE(mem_.CreateAnonymous(kShmemSize)); |
| 137 EXPECT_CALL(mock_delegate_factory_, MockCreateDelegate(NotNull())) |
| 138 .WillOnce(SaveArg<0>(&delegate_event_handler_)); |
| 139 } |
| 140 |
| 141 base::MessageLoop loop_; |
| 142 base::CancelableSyncSocket local_, foreign_socket_; |
| 143 base::SharedMemory mem_; |
| 144 StrictMock<MockDelegate>* delegate_ = nullptr; |
| 145 AudioOutputDelegate::EventHandler* delegate_event_handler_ = nullptr; |
| 146 StrictMock<MockDelegateFactory> mock_delegate_factory_; |
| 147 StrictMock<MockDeleter> deleter_; |
| 148 MockClient client_; |
| 149 std::unique_ptr<MojoAudioOutputStream> impl_; |
| 150 }; |
| 151 |
| 152 TEST_F(MojoAudioOutputStreamTest, Play_Plays) { |
| 153 AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput(); |
| 154 EXPECT_CALL(*delegate_, OnPlayStream()); |
| 155 |
| 156 audio_output_ptr->Play(); |
| 157 base::RunLoop().RunUntilIdle(); |
| 158 } |
| 159 |
| 160 TEST_F(MojoAudioOutputStreamTest, Pause_Pauses) { |
| 161 AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput(); |
| 162 EXPECT_CALL(*delegate_, OnPauseStream()); |
| 163 |
| 164 audio_output_ptr->Pause(); |
| 165 base::RunLoop().RunUntilIdle(); |
| 166 } |
| 167 |
| 168 TEST_F(MojoAudioOutputStreamTest, SetVolume_SetsVolume) { |
| 169 AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput(); |
| 170 EXPECT_CALL(*delegate_, OnSetVolume(kNewVolume)); |
| 171 |
| 172 audio_output_ptr->SetVolume(kNewVolume); |
| 173 base::RunLoop().RunUntilIdle(); |
| 174 } |
| 175 |
| 176 TEST_F(MojoAudioOutputStreamTest, DestructWithCallPending_Safe) { |
| 177 AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput(); |
| 178 base::RunLoop().RunUntilIdle(); |
| 179 |
| 180 ASSERT_NE(nullptr, delegate_event_handler_); |
| 181 delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
| 182 audio_output_ptr->Play(); |
| 183 impl_.reset(); |
| 184 base::RunLoop().RunUntilIdle(); |
| 185 } |
| 186 |
| 187 TEST_F(MojoAudioOutputStreamTest, Created_NotifiesClient) { |
| 188 AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput(); |
| 189 base::RunLoop().RunUntilIdle(); |
| 190 |
| 191 EXPECT_CALL(client_, GotNotification()); |
| 192 |
| 193 ASSERT_NE(nullptr, delegate_event_handler_); |
| 194 delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
| 195 |
| 196 base::RunLoop().RunUntilIdle(); |
| 197 } |
| 198 |
| 199 TEST_F(MojoAudioOutputStreamTest, SetVolumeTooLarge_Error) { |
| 200 AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput(); |
| 201 EXPECT_CALL(deleter_, Finished()); |
| 202 |
| 203 audio_output_ptr->SetVolume(15); |
| 204 base::RunLoop().RunUntilIdle(); |
| 205 Mock::VerifyAndClear(&deleter_); |
| 206 } |
| 207 |
| 208 TEST_F(MojoAudioOutputStreamTest, SetVolumeNegative_Error) { |
| 209 AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput(); |
| 210 EXPECT_CALL(deleter_, Finished()); |
| 211 |
| 212 audio_output_ptr->SetVolume(-0.5); |
| 213 base::RunLoop().RunUntilIdle(); |
| 214 Mock::VerifyAndClear(&deleter_); |
| 215 } |
| 216 |
| 217 TEST_F(MojoAudioOutputStreamTest, DelegateErrorBeforeCreated_PropagatesError) { |
| 218 AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput(); |
| 219 EXPECT_CALL(deleter_, Finished()); |
| 220 |
| 221 ASSERT_NE(nullptr, delegate_event_handler_); |
| 222 delegate_event_handler_->OnStreamError(kStreamId); |
| 223 |
| 224 base::RunLoop().RunUntilIdle(); |
| 225 Mock::VerifyAndClear(&deleter_); |
| 226 } |
| 227 |
| 228 TEST_F(MojoAudioOutputStreamTest, DelegateErrorAfterCreated_PropagatesError) { |
| 229 AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput(); |
| 230 EXPECT_CALL(deleter_, Finished()); |
| 231 base::RunLoop().RunUntilIdle(); |
| 232 |
| 233 ASSERT_NE(nullptr, delegate_event_handler_); |
| 234 delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
| 235 delegate_event_handler_->OnStreamError(kStreamId); |
| 236 |
| 237 base::RunLoop().RunUntilIdle(); |
| 238 Mock::VerifyAndClear(&deleter_); |
| 239 } |
| 240 |
| 241 TEST_F(MojoAudioOutputStreamTest, RemoteEndGone_Error) { |
| 242 AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput(); |
| 243 EXPECT_CALL(deleter_, Finished()); |
| 244 audio_output_ptr.reset(); |
| 245 base::RunLoop().RunUntilIdle(); |
| 246 Mock::VerifyAndClear(&deleter_); |
| 247 } |
| 248 |
| 249 } // namespace media |
OLD | NEW |