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 "content/browser/renderer_host/media/audio_output_impl.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 "content/common/media/audio_output.mojom.h" |
| 14 #include "media/audio/audio_output_controller.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 content { |
| 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, |
| 40 scoped_refptr<media::AudioOutputController>()); |
| 41 MOCK_CONST_METHOD0(GetStreamId, int()); |
| 42 MOCK_METHOD0(OnPlayStream, void()); |
| 43 MOCK_METHOD0(OnPauseStream, void()); |
| 44 MOCK_METHOD1(OnSetVolume, void(double)); |
| 45 }; |
| 46 |
| 47 class MockDelegateFactory { |
| 48 public: |
| 49 void PrepareDelegateForCreation( |
| 50 std::unique_ptr<AudioOutputDelegate> delegate) { |
| 51 ASSERT_EQ(nullptr, delegate_); |
| 52 delegate_.swap(delegate); |
| 53 } |
| 54 |
| 55 std::unique_ptr<AudioOutputDelegate> CreateDelegate( |
| 56 AudioOutputDelegate::EventHandler* handler, |
| 57 const media::AudioParameters& params) { |
| 58 MockCreateDelegate(handler, params); |
| 59 EXPECT_NE(nullptr, delegate_); |
| 60 return std::move(delegate_); |
| 61 } |
| 62 |
| 63 MOCK_METHOD2(MockCreateDelegate, |
| 64 void(AudioOutputDelegate::EventHandler*, |
| 65 const media::AudioParameters&)); |
| 66 |
| 67 private: |
| 68 std::unique_ptr<AudioOutputDelegate> delegate_; |
| 69 }; |
| 70 |
| 71 class MockFinishedListener { |
| 72 public: |
| 73 MOCK_METHOD1(Finished, void(AudioOutput*)); |
| 74 }; |
| 75 |
| 76 class MockClient { |
| 77 public: |
| 78 MockClient() {} |
| 79 |
| 80 void Started(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 } // namespace |
| 110 |
| 111 class AudioOutputImplTest : public Test { |
| 112 public: |
| 113 AudioOutputImplTest() |
| 114 : impl_(base::MakeUnique<AudioOutputImpl>( |
| 115 mojo::MakeRequest(&audio_output_ptr_), |
| 116 base::BindOnce(&MockDelegateFactory::CreateDelegate, |
| 117 base::Unretained(&mock_delegate_factory_)), |
| 118 base::BindOnce(&MockFinishedListener::Finished, |
| 119 base::Unretained(&listener_)))) {} |
| 120 |
| 121 void ExpectDelegateCreation() { |
| 122 delegate_ = new StrictMock<MockDelegate>(); |
| 123 mock_delegate_factory_.PrepareDelegateForCreation( |
| 124 base::WrapUnique(delegate_)); |
| 125 EXPECT_TRUE( |
| 126 base::CancelableSyncSocket::CreatePair(&local_, &foreign_socket_)); |
| 127 EXPECT_TRUE(mem_.CreateAnonymous(100)); |
| 128 EXPECT_CALL(mock_delegate_factory_, MockCreateDelegate(NotNull(), _)) |
| 129 .WillOnce(SaveArg<0>(&delegate_event_handler_)); |
| 130 } |
| 131 |
| 132 base::MessageLoop loop_; |
| 133 base::CancelableSyncSocket local_, foreign_socket_; |
| 134 base::SharedMemory mem_; |
| 135 StrictMock<MockDelegate>* delegate_ = nullptr; |
| 136 AudioOutputDelegate::EventHandler* delegate_event_handler_ = nullptr; |
| 137 StrictMock<MockDelegateFactory> mock_delegate_factory_; |
| 138 StrictMock<MockFinishedListener> listener_; |
| 139 AudioOutputPtr audio_output_ptr_; |
| 140 std::unique_ptr<AudioOutputImpl> impl_; |
| 141 }; |
| 142 |
| 143 TEST_F(AudioOutputImplTest, Play_Plays) { |
| 144 ExpectDelegateCreation(); |
| 145 MockClient client; |
| 146 audio_output_ptr_->Start( |
| 147 media::AudioParameters::UnavailableDeviceParams(), |
| 148 base::Bind(&MockClient::Started, base::Unretained(&client))); |
| 149 audio_output_ptr_->Play(); |
| 150 base::RunLoop().RunUntilIdle(); |
| 151 |
| 152 // AudioOutputImpl has to wait with playing until it has been constructed. |
| 153 // Same for other operations. |
| 154 EXPECT_CALL(*delegate_, OnPlayStream()); |
| 155 ASSERT_NE(nullptr, delegate_event_handler_); |
| 156 delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
| 157 base::RunLoop().RunUntilIdle(); |
| 158 } |
| 159 |
| 160 TEST_F(AudioOutputImplTest, Pause_Pauses) { |
| 161 ExpectDelegateCreation(); |
| 162 MockClient client; |
| 163 audio_output_ptr_->Start( |
| 164 media::AudioParameters::UnavailableDeviceParams(), |
| 165 base::Bind(&MockClient::Started, base::Unretained(&client))); |
| 166 audio_output_ptr_->Pause(); |
| 167 base::RunLoop().RunUntilIdle(); |
| 168 |
| 169 EXPECT_CALL(*delegate_, OnPauseStream()); |
| 170 ASSERT_NE(nullptr, delegate_event_handler_); |
| 171 delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
| 172 base::RunLoop().RunUntilIdle(); |
| 173 } |
| 174 |
| 175 TEST_F(AudioOutputImplTest, SetVolume_SetsVolume) { |
| 176 ExpectDelegateCreation(); |
| 177 MockClient client; |
| 178 audio_output_ptr_->Start( |
| 179 media::AudioParameters::UnavailableDeviceParams(), |
| 180 base::Bind(&MockClient::Started, base::Unretained(&client))); |
| 181 audio_output_ptr_->SetVolume(kNewVolume); |
| 182 base::RunLoop().RunUntilIdle(); |
| 183 |
| 184 EXPECT_CALL(*delegate_, OnSetVolume(kNewVolume)); |
| 185 ASSERT_NE(nullptr, delegate_event_handler_); |
| 186 delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
| 187 base::RunLoop().RunUntilIdle(); |
| 188 } |
| 189 |
| 190 TEST_F(AudioOutputImplTest, DestructWithCallPending_CancelsCall) { |
| 191 ExpectDelegateCreation(); |
| 192 MockClient client; |
| 193 audio_output_ptr_->Start( |
| 194 media::AudioParameters::UnavailableDeviceParams(), |
| 195 base::Bind(&MockClient::Started, base::Unretained(&client))); |
| 196 base::RunLoop().RunUntilIdle(); |
| 197 ASSERT_NE(nullptr, delegate_event_handler_); |
| 198 delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
| 199 audio_output_ptr_->Play(); |
| 200 impl_.reset(); |
| 201 |
| 202 base::RunLoop().RunUntilIdle(); |
| 203 } |
| 204 |
| 205 TEST_F(AudioOutputImplTest, Start_NotifiesClient) { |
| 206 ExpectDelegateCreation(); |
| 207 MockClient client; |
| 208 |
| 209 audio_output_ptr_->Start( |
| 210 media::AudioParameters::UnavailableDeviceParams(), |
| 211 base::Bind(&MockClient::Started, base::Unretained(&client))); |
| 212 base::RunLoop().RunUntilIdle(); |
| 213 |
| 214 EXPECT_CALL(client, GotNotification()); |
| 215 |
| 216 ASSERT_NE(nullptr, delegate_event_handler_); |
| 217 delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
| 218 |
| 219 base::RunLoop().RunUntilIdle(); |
| 220 } |
| 221 |
| 222 TEST_F(AudioOutputImplTest, PlayBeforeStart_Error) { |
| 223 EXPECT_CALL(listener_, Finished(impl_.get())); |
| 224 audio_output_ptr_->Play(); |
| 225 base::RunLoop().RunUntilIdle(); |
| 226 } |
| 227 |
| 228 TEST_F(AudioOutputImplTest, PauseBeforeStart_Error) { |
| 229 EXPECT_CALL(listener_, Finished(impl_.get())); |
| 230 audio_output_ptr_->Pause(); |
| 231 base::RunLoop().RunUntilIdle(); |
| 232 } |
| 233 |
| 234 TEST_F(AudioOutputImplTest, SetVolumeBeforeStart_Error) { |
| 235 EXPECT_CALL(listener_, Finished(impl_.get())); |
| 236 audio_output_ptr_->SetVolume(kNewVolume); |
| 237 base::RunLoop().RunUntilIdle(); |
| 238 } |
| 239 |
| 240 TEST_F(AudioOutputImplTest, SetVolumeTooLarge_Error) { |
| 241 ExpectDelegateCreation(); |
| 242 EXPECT_CALL(listener_, Finished(impl_.get())); |
| 243 MockClient client; |
| 244 audio_output_ptr_->Start( |
| 245 media::AudioParameters::UnavailableDeviceParams(), |
| 246 base::Bind(&MockClient::Started, base::Unretained(&client))); |
| 247 audio_output_ptr_->SetVolume(15); |
| 248 base::RunLoop().RunUntilIdle(); |
| 249 ASSERT_NE(nullptr, delegate_event_handler_); |
| 250 delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
| 251 |
| 252 base::RunLoop().RunUntilIdle(); |
| 253 } |
| 254 |
| 255 TEST_F(AudioOutputImplTest, SetVolumeNegative_Error) { |
| 256 ExpectDelegateCreation(); |
| 257 EXPECT_CALL(listener_, Finished(impl_.get())); |
| 258 MockClient client; |
| 259 audio_output_ptr_->Start( |
| 260 media::AudioParameters::UnavailableDeviceParams(), |
| 261 base::Bind(&MockClient::Started, base::Unretained(&client))); |
| 262 audio_output_ptr_->SetVolume(-0.5); |
| 263 base::RunLoop().RunUntilIdle(); |
| 264 ASSERT_NE(nullptr, delegate_event_handler_); |
| 265 delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
| 266 |
| 267 base::RunLoop().RunUntilIdle(); |
| 268 } |
| 269 |
| 270 TEST_F(AudioOutputImplTest, StartStart_Error) { |
| 271 MockClient client; |
| 272 ExpectDelegateCreation(); |
| 273 EXPECT_CALL(listener_, Finished(impl_.get())); |
| 274 audio_output_ptr_->Start( |
| 275 media::AudioParameters::UnavailableDeviceParams(), |
| 276 base::Bind(&MockClient::Started, base::Unretained(&client))); |
| 277 audio_output_ptr_->Start( |
| 278 media::AudioParameters::UnavailableDeviceParams(), |
| 279 base::Bind(&MockClient::Started, base::Unretained(&client))); |
| 280 base::RunLoop().RunUntilIdle(); |
| 281 ASSERT_NE(nullptr, delegate_event_handler_); |
| 282 delegate_event_handler_->OnStreamCreated( |
| 283 kStreamId, &mem_, &foreign_socket_); // Should be enough to trigger the |
| 284 // error, as the first Start call |
| 285 // will finish and the next will be |
| 286 // processed. |
| 287 base::RunLoop().RunUntilIdle(); |
| 288 } |
| 289 |
| 290 TEST_F(AudioOutputImplTest, DelegateErrorBeforeCreated_PropagatesError) { |
| 291 ExpectDelegateCreation(); |
| 292 MockClient client; |
| 293 EXPECT_CALL(listener_, Finished(impl_.get())); |
| 294 |
| 295 audio_output_ptr_->Start( |
| 296 media::AudioParameters::UnavailableDeviceParams(), |
| 297 base::Bind(&MockClient::Started, base::Unretained(&client))); |
| 298 base::RunLoop().RunUntilIdle(); |
| 299 |
| 300 ASSERT_NE(nullptr, delegate_event_handler_); |
| 301 delegate_event_handler_->OnStreamError(kStreamId); |
| 302 |
| 303 base::RunLoop().RunUntilIdle(); |
| 304 } |
| 305 |
| 306 TEST_F(AudioOutputImplTest, DelegateErrorAfterCreated_PropagatesError) { |
| 307 ExpectDelegateCreation(); |
| 308 MockClient client; |
| 309 EXPECT_CALL(listener_, Finished(impl_.get())); |
| 310 |
| 311 audio_output_ptr_->Start( |
| 312 media::AudioParameters::UnavailableDeviceParams(), |
| 313 base::Bind(&MockClient::Started, base::Unretained(&client))); |
| 314 base::RunLoop().RunUntilIdle(); |
| 315 |
| 316 ASSERT_NE(nullptr, delegate_event_handler_); |
| 317 delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
| 318 delegate_event_handler_->OnStreamError(kStreamId); |
| 319 |
| 320 base::RunLoop().RunUntilIdle(); |
| 321 } |
| 322 |
| 323 TEST_F(AudioOutputImplTest, RemoteEndGone_Error) { |
| 324 EXPECT_CALL(listener_, Finished(impl_.get())); |
| 325 audio_output_ptr_.reset(); |
| 326 base::RunLoop().RunUntilIdle(); |
| 327 Mock::VerifyAndClear(&listener_); |
| 328 } |
| 329 |
| 330 TEST_F(AudioOutputImplTest, |
| 331 RemoteEndGoneWhileWaitingForDelegateCreation_Error) { |
| 332 ExpectDelegateCreation(); |
| 333 MockClient client; |
| 334 EXPECT_CALL(listener_, Finished(impl_.get())); |
| 335 audio_output_ptr_->Start( |
| 336 media::AudioParameters::UnavailableDeviceParams(), |
| 337 base::Bind(&MockClient::Started, base::Unretained(&client))); |
| 338 base::RunLoop().RunUntilIdle(); |
| 339 audio_output_ptr_.reset(); |
| 340 |
| 341 ASSERT_NE(nullptr, delegate_event_handler_); |
| 342 delegate_event_handler_->OnStreamCreated(kStreamId, &mem_, &foreign_socket_); |
| 343 base::RunLoop().RunUntilIdle(); |
| 344 Mock::VerifyAndClear(&listener_); |
| 345 } |
| 346 |
| 347 } // namespace content |
OLD | NEW |