OLD | NEW |
(Empty) | |
| 1 // Copyright 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 "media/mojo/services/mojo_audio_output.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.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 |
| 27 using testing::_; |
| 28 using testing::Mock; |
| 29 using testing::NotNull; |
| 30 using testing::Return; |
| 31 using testing::SaveArg; |
| 32 using testing::StrictMock; |
| 33 using testing::Test; |
| 34 using AudioOutput = mojom::AudioOutput; |
| 35 using AudioOutputPtr = mojo::InterfacePtr<AudioOutput>; |
| 36 |
| 37 class MockDelegate : public AudioOutputDelegate { |
| 38 public: |
| 39 MOCK_CONST_METHOD0(GetController, scoped_refptr<AudioOutputController>()); |
| 40 MOCK_CONST_METHOD0(GetStreamId, int()); |
| 41 MOCK_METHOD0(OnPlayStream, void()); |
| 42 MOCK_METHOD0(OnPauseStream, void()); |
| 43 MOCK_METHOD1(OnSetVolume, void(double)); |
| 44 }; |
| 45 |
| 46 class MockDelegateFactory { |
| 47 public: |
| 48 void PrepareDelegateForCreation( |
| 49 std::unique_ptr<AudioOutputDelegate> delegate) { |
| 50 ASSERT_EQ(nullptr, delegate_); |
| 51 delegate_.swap(delegate); |
| 52 } |
| 53 |
| 54 std::unique_ptr<AudioOutputDelegate> CreateDelegate( |
| 55 AudioOutputDelegate::EventHandler* handler, |
| 56 const AudioParameters& params) { |
| 57 MockCreateDelegate(handler, params); |
| 58 EXPECT_NE(nullptr, delegate_); |
| 59 return std::move(delegate_); |
| 60 } |
| 61 |
| 62 MOCK_METHOD2(MockCreateDelegate, |
| 63 void(AudioOutputDelegate::EventHandler*, |
| 64 const AudioParameters&)); |
| 65 |
| 66 private: |
| 67 std::unique_ptr<AudioOutputDelegate> delegate_; |
| 68 }; |
| 69 |
| 70 class MockFinishedListener { |
| 71 public: |
| 72 MOCK_METHOD1(Finished, void(AudioOutput*)); |
| 73 }; |
| 74 |
| 75 class MockClient { |
| 76 public: |
| 77 MockClient() {} |
| 78 |
| 79 void Initialized(mojo::ScopedSharedBufferHandle shared_buffer, |
| 80 mojo::ScopedHandle socket_handle) { |
| 81 ASSERT_TRUE(shared_buffer.is_valid()); |
| 82 ASSERT_TRUE(socket_handle.is_valid()); |
| 83 |
| 84 base::PlatformFile fd; |
| 85 mojo::UnwrapPlatformFile(std::move(socket_handle), &fd); |
| 86 socket_ = base::MakeUnique<base::CancelableSyncSocket>(fd); |
| 87 EXPECT_NE(socket_->handle(), base::CancelableSyncSocket::kInvalidHandle); |
| 88 |
| 89 size_t memory_length; |
| 90 base::SharedMemoryHandle shmem_handle; |
| 91 bool read_only; |
| 92 EXPECT_EQ( |
| 93 mojo::UnwrapSharedMemoryHandle(std::move(shared_buffer), &shmem_handle, |
| 94 &memory_length, &read_only), |
| 95 MOJO_RESULT_OK); |
| 96 EXPECT_FALSE(read_only); |
| 97 buffer_ = base::MakeUnique<base::SharedMemory>(shmem_handle, read_only); |
| 98 |
| 99 GotNotification(); |
| 100 } |
| 101 |
| 102 MOCK_METHOD0(GotNotification, void()); |
| 103 |
| 104 private: |
| 105 std::unique_ptr<base::SharedMemory> buffer_; |
| 106 std::unique_ptr<base::CancelableSyncSocket> socket_; |
| 107 }; |
| 108 } // namespace |
| 109 |
| 110 class MojoAudioOutputTest : public Test { |
| 111 public: |
| 112 MojoAudioOutputTest() |
| 113 : impl_(base::MakeUnique<MojoAudioOutput>( |
| 114 mojo::MakeRequest(&audio_output_ptr_), |
| 115 base::BindOnce(&MockDelegateFactory::CreateDelegate, |
| 116 base::Unretained(&mock_delegate_factory_)), |
| 117 base::BindOnce(&MockFinishedListener::Finished, |
| 118 base::Unretained(&listener_)))) {} |
| 119 |
| 120 void ExpectDelegateCreation() { |
| 121 delegate_ = new StrictMock<MockDelegate>(); |
| 122 mock_delegate_factory_.PrepareDelegateForCreation( |
| 123 base::WrapUnique(delegate_)); |
| 124 EXPECT_TRUE( |
| 125 base::CancelableSyncSocket::CreatePair(&local_, &foreign_socket_)); |
| 126 EXPECT_TRUE(mem_.CreateAnonymous(100)); |
| 127 EXPECT_CALL(mock_delegate_factory_, MockCreateDelegate(NotNull(), _)) |
| 128 .WillOnce(SaveArg<0>(&delegate_event_handler_)); |
| 129 } |
| 130 |
| 131 base::MessageLoop loop_; |
| 132 base::CancelableSyncSocket local_, foreign_socket_; |
| 133 base::SharedMemory mem_; |
| 134 StrictMock<MockDelegate>* delegate_ = nullptr; |
| 135 AudioOutputDelegate::EventHandler* delegate_event_handler_ = nullptr; |
| 136 StrictMock<MockDelegateFactory> mock_delegate_factory_; |
| 137 StrictMock<MockFinishedListener> listener_; |
| 138 AudioOutputPtr audio_output_ptr_; |
| 139 std::unique_ptr<MojoAudioOutput> impl_; |
| 140 }; |
| 141 |
| 142 TEST_F(MojoAudioOutputTest, Play_Plays) { |
| 143 ExpectDelegateCreation(); |
| 144 EXPECT_CALL(*delegate_, OnPlayStream()); |
| 145 MockClient client; |
| 146 audio_output_ptr_->Initialize( |
| 147 AudioParameters::UnavailableDeviceParams(), |
| 148 base::Bind(&MockClient::Initialized, base::Unretained(&client))); |
| 149 audio_output_ptr_->Play(); |
| 150 base::RunLoop().RunUntilIdle(); |
| 151 } |
| 152 |
| 153 TEST_F(MojoAudioOutputTest, Pause_Pauses) { |
| 154 ExpectDelegateCreation(); |
| 155 EXPECT_CALL(*delegate_, OnPauseStream()); |
| 156 MockClient client; |
| 157 audio_output_ptr_->Initialize( |
| 158 AudioParameters::UnavailableDeviceParams(), |
| 159 base::Bind(&MockClient::Initialized, base::Unretained(&client))); |
| 160 audio_output_ptr_->Pause(); |
| 161 base::RunLoop().RunUntilIdle(); |
| 162 } |
| 163 |
| 164 TEST_F(MojoAudioOutputTest, SetVolume_SetsVolume) { |
| 165 ExpectDelegateCreation(); |
| 166 EXPECT_CALL(*delegate_, OnSetVolume(kNewVolume)); |
| 167 MockClient client; |
| 168 audio_output_ptr_->Initialize( |
| 169 AudioParameters::UnavailableDeviceParams(), |
| 170 base::Bind(&MockClient::Initialized, base::Unretained(&client))); |
| 171 audio_output_ptr_->SetVolume(kNewVolume); |
| 172 base::RunLoop().RunUntilIdle(); |
| 173 } |
| 174 |
| 175 TEST_F(MojoAudioOutputTest, DestructWithCallPending_CancelsCall) { |
| 176 ExpectDelegateCreation(); |
| 177 MockClient client; |
| 178 audio_output_ptr_->Initialize( |
| 179 AudioParameters::UnavailableDeviceParams(), |
| 180 base::Bind(&MockClient::Initialized, base::Unretained(&client))); |
| 181 base::RunLoop().RunUntilIdle(); |
| 182 |
| 183 ASSERT_NE(nullptr, delegate_event_handler_); |
| 184 delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
| 185 audio_output_ptr_->Play(); |
| 186 impl_.reset(); |
| 187 base::RunLoop().RunUntilIdle(); |
| 188 } |
| 189 |
| 190 TEST_F(MojoAudioOutputTest, Initialize_NotifiesClient) { |
| 191 ExpectDelegateCreation(); |
| 192 MockClient client; |
| 193 audio_output_ptr_->Initialize( |
| 194 AudioParameters::UnavailableDeviceParams(), |
| 195 base::Bind(&MockClient::Initialized, base::Unretained(&client))); |
| 196 base::RunLoop().RunUntilIdle(); |
| 197 |
| 198 EXPECT_CALL(client, GotNotification()); |
| 199 |
| 200 ASSERT_NE(nullptr, delegate_event_handler_); |
| 201 delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
| 202 |
| 203 base::RunLoop().RunUntilIdle(); |
| 204 } |
| 205 |
| 206 TEST_F(MojoAudioOutputTest, PlayBeforeInitialize_Error) { |
| 207 EXPECT_CALL(listener_, Finished(impl_.get())); |
| 208 audio_output_ptr_->Play(); |
| 209 base::RunLoop().RunUntilIdle(); |
| 210 } |
| 211 |
| 212 TEST_F(MojoAudioOutputTest, PauseBeforeInitialize_Error) { |
| 213 EXPECT_CALL(listener_, Finished(impl_.get())); |
| 214 audio_output_ptr_->Pause(); |
| 215 base::RunLoop().RunUntilIdle(); |
| 216 } |
| 217 |
| 218 TEST_F(MojoAudioOutputTest, SetVolumeBeforeInitialize_Error) { |
| 219 EXPECT_CALL(listener_, Finished(impl_.get())); |
| 220 audio_output_ptr_->SetVolume(kNewVolume); |
| 221 base::RunLoop().RunUntilIdle(); |
| 222 } |
| 223 |
| 224 TEST_F(MojoAudioOutputTest, SetVolumeTooLarge_Error) { |
| 225 ExpectDelegateCreation(); |
| 226 EXPECT_CALL(listener_, Finished(impl_.get())); |
| 227 MockClient client; |
| 228 audio_output_ptr_->Initialize( |
| 229 AudioParameters::UnavailableDeviceParams(), |
| 230 base::Bind(&MockClient::Initialized, base::Unretained(&client))); |
| 231 audio_output_ptr_->SetVolume(15); |
| 232 base::RunLoop().RunUntilIdle(); |
| 233 ASSERT_NE(nullptr, delegate_event_handler_); |
| 234 delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
| 235 |
| 236 base::RunLoop().RunUntilIdle(); |
| 237 } |
| 238 |
| 239 TEST_F(MojoAudioOutputTest, SetVolumeNegative_Error) { |
| 240 ExpectDelegateCreation(); |
| 241 EXPECT_CALL(listener_, Finished(impl_.get())); |
| 242 MockClient client; |
| 243 audio_output_ptr_->Initialize( |
| 244 AudioParameters::UnavailableDeviceParams(), |
| 245 base::Bind(&MockClient::Initialized, base::Unretained(&client))); |
| 246 audio_output_ptr_->SetVolume(-0.5); |
| 247 base::RunLoop().RunUntilIdle(); |
| 248 ASSERT_NE(nullptr, delegate_event_handler_); |
| 249 delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
| 250 |
| 251 base::RunLoop().RunUntilIdle(); |
| 252 } |
| 253 |
| 254 TEST_F(MojoAudioOutputTest, InitializeStart_Error) { |
| 255 MockClient client; |
| 256 ExpectDelegateCreation(); |
| 257 EXPECT_CALL(listener_, Finished(impl_.get())); |
| 258 audio_output_ptr_->Initialize( |
| 259 AudioParameters::UnavailableDeviceParams(), |
| 260 base::Bind(&MockClient::Initialized, base::Unretained(&client))); |
| 261 audio_output_ptr_->Initialize( |
| 262 AudioParameters::UnavailableDeviceParams(), |
| 263 base::Bind(&MockClient::Initialized, base::Unretained(&client))); |
| 264 base::RunLoop().RunUntilIdle(); |
| 265 } |
| 266 |
| 267 TEST_F(MojoAudioOutputTest, DelegateErrorBeforeCreated_PropagatesError) { |
| 268 ExpectDelegateCreation(); |
| 269 MockClient client; |
| 270 EXPECT_CALL(listener_, Finished(impl_.get())); |
| 271 |
| 272 audio_output_ptr_->Initialize( |
| 273 AudioParameters::UnavailableDeviceParams(), |
| 274 base::Bind(&MockClient::Initialized, base::Unretained(&client))); |
| 275 base::RunLoop().RunUntilIdle(); |
| 276 |
| 277 ASSERT_NE(nullptr, delegate_event_handler_); |
| 278 delegate_event_handler_->OnStreamError(kStreamId); |
| 279 |
| 280 base::RunLoop().RunUntilIdle(); |
| 281 } |
| 282 |
| 283 TEST_F(MojoAudioOutputTest, DelegateErrorAfterCreated_PropagatesError) { |
| 284 ExpectDelegateCreation(); |
| 285 MockClient client; |
| 286 EXPECT_CALL(listener_, Finished(impl_.get())); |
| 287 |
| 288 audio_output_ptr_->Initialize( |
| 289 AudioParameters::UnavailableDeviceParams(), |
| 290 base::Bind(&MockClient::Initialized, base::Unretained(&client))); |
| 291 base::RunLoop().RunUntilIdle(); |
| 292 |
| 293 ASSERT_NE(nullptr, delegate_event_handler_); |
| 294 delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
| 295 delegate_event_handler_->OnStreamError(kStreamId); |
| 296 |
| 297 base::RunLoop().RunUntilIdle(); |
| 298 } |
| 299 |
| 300 TEST_F(MojoAudioOutputTest, RemoteEndGone_Error) { |
| 301 EXPECT_CALL(listener_, Finished(impl_.get())); |
| 302 audio_output_ptr_.reset(); |
| 303 base::RunLoop().RunUntilIdle(); |
| 304 Mock::VerifyAndClear(&listener_); |
| 305 } |
| 306 |
| 307 TEST_F(MojoAudioOutputTest, |
| 308 RemoteEndGoneWhileWaitingForDelegateCreation_Error) { |
| 309 // Tests the following sequence of events: |
| 310 // MojoAudioOutput is constructed and started. |
| 311 // MojoAudioOutput gets connection error. |
| 312 // MojoAudioOutput gets event that delegate has finished creating. |
| 313 ExpectDelegateCreation(); |
| 314 MockClient client; |
| 315 EXPECT_CALL(listener_, Finished(impl_.get())); |
| 316 audio_output_ptr_->Initialize( |
| 317 AudioParameters::UnavailableDeviceParams(), |
| 318 base::Bind(&MockClient::Initialized, base::Unretained(&client))); |
| 319 base::RunLoop().RunUntilIdle(); |
| 320 audio_output_ptr_.reset(); |
| 321 |
| 322 ASSERT_NE(nullptr, delegate_event_handler_); |
| 323 delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
| 324 base::RunLoop().RunUntilIdle(); |
| 325 Mock::VerifyAndClear(&listener_); |
| 326 } |
| 327 |
| 328 } // namespace media |
OLD | NEW |