1 // Copyright 2013 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 "base/message_loop/message_loop.h" 6 #include "base/strings/stringprintf.h" 7 #include "media/audio/alsa/alsa_output.h" 8 #include "media/audio/alsa/alsa_wrapper.h" 9 #include "media/audio/alsa/audio_manager_alsa.h" 10 #include "media/audio/fake_audio_log_factory.h" 11 #include "media/base/data_buffer.h" 12 #include "media/base/seekable_buffer.h" 13 #include "testing/gmock/include/gmock/gmock.h" 14 #include "testing/gtest/include/gtest/gtest.h" 15 16 using testing::_; 17 using testing::AllOf; 18 using testing::AtLeast; 19 using testing::DoAll; 20 using testing::Field; 21 using testing::InSequence; 22 using testing::Invoke; 23 using testing::InvokeWithoutArgs; 24 using testing::Mock; 25 using testing::MockFunction; 26 using testing::Return; 27 using testing::SetArgumentPointee; 28 using testing::StrictMock; 29 using testing::StrEq; 30 using testing::Unused; 31 32 namespace media { 33 34 class MockAlsaWrapper : public AlsaWrapper { 35 public: 36 MOCK_METHOD3(DeviceNameHint, int(int card, 37 const char* iface, 38 void*** hints)); 39 MOCK_METHOD2(DeviceNameGetHint, char*(const void* hint, const char* id)); 40 MOCK_METHOD1(DeviceNameFreeHint, int(void** hints)); 41 42 MOCK_METHOD4(PcmOpen, int(snd_pcm_t** handle, const char* name, 43 snd_pcm_stream_t stream, int mode)); 44 MOCK_METHOD1(PcmClose, int(snd_pcm_t* handle)); 45 MOCK_METHOD1(PcmPrepare, int(snd_pcm_t* handle)); 46 MOCK_METHOD1(PcmDrop, int(snd_pcm_t* handle)); 47 MOCK_METHOD2(PcmDelay, int(snd_pcm_t* handle, snd_pcm_sframes_t* delay)); 48 MOCK_METHOD3(PcmWritei, snd_pcm_sframes_t(snd_pcm_t* handle, 49 const void* buffer, 50 snd_pcm_uframes_t size)); 51 MOCK_METHOD3(PcmReadi, snd_pcm_sframes_t(snd_pcm_t* handle, 52 void* buffer, 53 snd_pcm_uframes_t size)); 54 MOCK_METHOD3(PcmRecover, int(snd_pcm_t* handle, int err, int silent)); 55 MOCK_METHOD7(PcmSetParams, int(snd_pcm_t* handle, snd_pcm_format_t format, 56 snd_pcm_access_t access, unsigned int channels, 57 unsigned int rate, int soft_resample, 58 unsigned int latency)); 59 MOCK_METHOD3(PcmGetParams, int(snd_pcm_t* handle, 60 snd_pcm_uframes_t* buffer_size, 61 snd_pcm_uframes_t* period_size)); 62 MOCK_METHOD1(PcmName, const char*(snd_pcm_t* handle)); 63 MOCK_METHOD1(PcmAvailUpdate, snd_pcm_sframes_t(snd_pcm_t* handle)); 64 MOCK_METHOD1(PcmState, snd_pcm_state_t(snd_pcm_t* handle)); 65 MOCK_METHOD1(PcmStart, int(snd_pcm_t* handle)); 66 67 MOCK_METHOD1(StrError, const char*(int errnum)); 68 }; 69 70 class MockAudioSourceCallback : public AudioOutputStream::AudioSourceCallback { 71 public: 72 MOCK_METHOD2(OnMoreData, int(AudioBus* audio_bus, 73 AudioBuffersState buffers_state)); 74 MOCK_METHOD3(OnMoreIOData, int(AudioBus* source, 75 AudioBus* dest, 76 AudioBuffersState buffers_state)); 77 MOCK_METHOD1(OnError, void(AudioOutputStream* stream)); 78 }; 79 80 class MockAudioManagerAlsa : public AudioManagerAlsa { 81 public: 82 MockAudioManagerAlsa() : AudioManagerAlsa(&fake_audio_log_factory_) {} 83 MOCK_METHOD0(Init, void()); 84 MOCK_METHOD0(HasAudioOutputDevices, bool()); 85 MOCK_METHOD0(HasAudioInputDevices, bool()); 86 MOCK_METHOD1(MakeLinearOutputStream, AudioOutputStream*( 87 const AudioParameters& params)); 88 MOCK_METHOD3(MakeLowLatencyOutputStream, AudioOutputStream*( 89 const AudioParameters& params, 90 const std::string& device_id, 91 const std::string& input_device_id)); 92 MOCK_METHOD2(MakeLowLatencyInputStream, AudioInputStream*( 93 const AudioParameters& params, const std::string& device_id)); 94 95 // We need to override this function in order to skip the checking the number 96 // of active output streams. It is because the number of active streams 97 // is managed inside MakeAudioOutputStream, and we don't use 98 // MakeAudioOutputStream to create the stream in the tests. 99 virtual void ReleaseOutputStream(AudioOutputStream* stream) OVERRIDE { 100 DCHECK(stream); 101 delete stream; 102 } 103 104 // We don't mock this method since all tests will do the same thing 105 // and use the current message loop. 106 virtual scoped_refptr<base::MessageLoopProxy> GetMessageLoop() OVERRIDE { 107 return base::MessageLoop::current()->message_loop_proxy(); 108 } 109 110 private: 111 FakeAudioLogFactory fake_audio_log_factory_; 112 }; 113 114 class AlsaPcmOutputStreamTest : public testing::Test { 115 protected: 116 AlsaPcmOutputStreamTest() { 117 mock_manager_.reset(new StrictMock<MockAudioManagerAlsa>()); 118 } 119 120 virtual ~AlsaPcmOutputStreamTest() { 121 } 122 123 AlsaPcmOutputStream* CreateStream(ChannelLayout layout) { 124 return CreateStream(layout, kTestFramesPerPacket); 125 } 126 127 AlsaPcmOutputStream* CreateStream(ChannelLayout layout, 128 int32 samples_per_packet) { 129 AudioParameters params(kTestFormat, layout, kTestSampleRate, 130 kTestBitsPerSample, samples_per_packet); 131 return new AlsaPcmOutputStream(kTestDeviceName, 132 params, 133 &mock_alsa_wrapper_, 134 mock_manager_.get()); 135 } 136 137 // Helper function to malloc the string returned by DeviceNameHint for NAME. 138 static char* EchoHint(const void* name, Unused) { 139 return strdup(static_cast<const char*>(name)); 140 } 141 142 // Helper function to malloc the string returned by DeviceNameHint for IOID. 143 static char* OutputHint(Unused, Unused) { 144 return strdup("Output"); 145 } 146 147 // Helper function to initialize |test_stream->buffer_|. Must be called 148 // in all tests that use buffer_ without opening the stream. 149 void InitBuffer(AlsaPcmOutputStream* test_stream) { 150 DCHECK(test_stream); 151 packet_ = new media::DataBuffer(kTestPacketSize); 152 packet_->set_data_size(kTestPacketSize); 153 test_stream->buffer_.reset(new media::SeekableBuffer(0, kTestPacketSize)); 154 test_stream->buffer_->Append(packet_.get()); 155 } 156 157 static const ChannelLayout kTestChannelLayout; 158 static const int kTestSampleRate; 159 static const int kTestBitsPerSample; 160 static const int kTestBytesPerFrame; 161 static const AudioParameters::Format kTestFormat; 162 static const char kTestDeviceName[]; 163 static const char kDummyMessage[]; 164 static const uint32 kTestFramesPerPacket; 165 static const int kTestPacketSize; 166 static const int kTestFailedErrno; 167 static snd_pcm_t* const kFakeHandle; 168 169 // Used to simulate DeviceNameHint. 170 static char kSurround40[]; 171 static char kSurround41[]; 172 static char kSurround50[]; 173 static char kSurround51[]; 174 static char kSurround70[]; 175 static char kSurround71[]; 176 static void* kFakeHints[]; 177 178 StrictMock<MockAlsaWrapper> mock_alsa_wrapper_; 179 scoped_ptr<StrictMock<MockAudioManagerAlsa> > mock_manager_; 180 base::MessageLoop message_loop_; 181 scoped_refptr<media::DataBuffer> packet_; 182 183 private: 184 DISALLOW_COPY_AND_ASSIGN(AlsaPcmOutputStreamTest); 185 }; 186 187 const ChannelLayout AlsaPcmOutputStreamTest::kTestChannelLayout = 188 CHANNEL_LAYOUT_STEREO; 189 const int AlsaPcmOutputStreamTest::kTestSampleRate = 190 AudioParameters::kAudioCDSampleRate; 191 const int AlsaPcmOutputStreamTest::kTestBitsPerSample = 8; 192 const int AlsaPcmOutputStreamTest::kTestBytesPerFrame = 193 AlsaPcmOutputStreamTest::kTestBitsPerSample / 8 * 194 ChannelLayoutToChannelCount(AlsaPcmOutputStreamTest::kTestChannelLayout); 195 const AudioParameters::Format AlsaPcmOutputStreamTest::kTestFormat = 196 AudioParameters::AUDIO_PCM_LINEAR; 197 const char AlsaPcmOutputStreamTest::kTestDeviceName[] = "TestDevice"; 198 const char AlsaPcmOutputStreamTest::kDummyMessage[] = "dummy"; 199 const uint32 AlsaPcmOutputStreamTest::kTestFramesPerPacket = 1000; 200 const int AlsaPcmOutputStreamTest::kTestPacketSize = 201 AlsaPcmOutputStreamTest::kTestFramesPerPacket * 202 AlsaPcmOutputStreamTest::kTestBytesPerFrame; 203 const int AlsaPcmOutputStreamTest::kTestFailedErrno = -EACCES; 204 snd_pcm_t* const AlsaPcmOutputStreamTest::kFakeHandle = 205 reinterpret_cast<snd_pcm_t*>(1); 206 207 char AlsaPcmOutputStreamTest::kSurround40[] = "surround40:CARD=foo,DEV=0"; 208 char AlsaPcmOutputStreamTest::kSurround41[] = "surround41:CARD=foo,DEV=0"; 209 char AlsaPcmOutputStreamTest::kSurround50[] = "surround50:CARD=foo,DEV=0"; 210 char AlsaPcmOutputStreamTest::kSurround51[] = "surround51:CARD=foo,DEV=0"; 211 char AlsaPcmOutputStreamTest::kSurround70[] = "surround70:CARD=foo,DEV=0"; 212 char AlsaPcmOutputStreamTest::kSurround71[] = "surround71:CARD=foo,DEV=0"; 213 void* AlsaPcmOutputStreamTest::kFakeHints[] = { 214 kSurround40, kSurround41, kSurround50, kSurround51, 215 kSurround70, kSurround71, NULL }; 216 217 // Custom action to clear a memory buffer. 218 ACTION(ClearBuffer) { 219 arg0->Zero(); 220 } 221 222 TEST_F(AlsaPcmOutputStreamTest, ConstructedState) { 223 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); 224 EXPECT_EQ(AlsaPcmOutputStream::kCreated, test_stream->state()); 225 test_stream->Close(); 226 227 // Should support mono. 228 test_stream = CreateStream(CHANNEL_LAYOUT_MONO); 229 EXPECT_EQ(AlsaPcmOutputStream::kCreated, test_stream->state()); 230 test_stream->Close(); 231 232 // Should support multi-channel. 233 test_stream = CreateStream(CHANNEL_LAYOUT_SURROUND); 234 EXPECT_EQ(AlsaPcmOutputStream::kCreated, test_stream->state()); 235 test_stream->Close(); 236 237 // Bad bits per sample. 238 AudioParameters bad_bps_params(kTestFormat, kTestChannelLayout, 239 kTestSampleRate, kTestBitsPerSample - 1, 240 kTestFramesPerPacket); 241 test_stream = new AlsaPcmOutputStream(kTestDeviceName, 242 bad_bps_params, 243 &mock_alsa_wrapper_, 244 mock_manager_.get()); 245 EXPECT_EQ(AlsaPcmOutputStream::kInError, test_stream->state()); 246 test_stream->Close(); 247 248 // Bad format. 249 AudioParameters bad_format_params( 250 AudioParameters::AUDIO_LAST_FORMAT, kTestChannelLayout, kTestSampleRate, 251 kTestBitsPerSample, kTestFramesPerPacket); 252 test_stream = new AlsaPcmOutputStream(kTestDeviceName, 253 bad_format_params, 254 &mock_alsa_wrapper_, 255 mock_manager_.get()); 256 EXPECT_EQ(AlsaPcmOutputStream::kInError, test_stream->state()); 257 test_stream->Close(); 258 } 259 260 TEST_F(AlsaPcmOutputStreamTest, LatencyFloor) { 261 const double kMicrosPerFrame = 262 static_cast<double>(1000000) / kTestSampleRate; 263 const double kPacketFramesInMinLatency = 264 AlsaPcmOutputStream::kMinLatencyMicros / kMicrosPerFrame / 2.0; 265 266 // Test that packets which would cause a latency under less than 267 // AlsaPcmOutputStream::kMinLatencyMicros will get clipped to 268 // AlsaPcmOutputStream::kMinLatencyMicros, 269 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _)) 270 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), 271 Return(0))); 272 EXPECT_CALL(mock_alsa_wrapper_, 273 PcmSetParams(_, _, _, _, _, _, 274 AlsaPcmOutputStream::kMinLatencyMicros)) 275 .WillOnce(Return(0)); 276 EXPECT_CALL(mock_alsa_wrapper_, PcmGetParams(_, _, _)) 277 .WillOnce(DoAll(SetArgumentPointee<1>(kTestFramesPerPacket), 278 SetArgumentPointee<2>(kTestFramesPerPacket / 2), 279 Return(0))); 280 281 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout, 282 kPacketFramesInMinLatency); 283 ASSERT_TRUE(test_stream->Open()); 284 285 // Now close it and test that everything was released. 286 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle)).WillOnce(Return(0)); 287 EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle)) 288 .WillOnce(Return(kTestDeviceName)); 289 test_stream->Close(); 290 291 Mock::VerifyAndClear(&mock_alsa_wrapper_); 292 Mock::VerifyAndClear(mock_manager_.get()); 293 294 // Test that having more packets ends up with a latency based on packet size. 295 const int kOverMinLatencyPacketSize = kPacketFramesInMinLatency + 1; 296 int64 expected_micros = AlsaPcmOutputStream::FramesToTimeDelta( 297 kOverMinLatencyPacketSize * 2, kTestSampleRate).InMicroseconds(); 298 299 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _)) 300 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), Return(0))); 301 EXPECT_CALL(mock_alsa_wrapper_, 302 PcmSetParams(_, _, _, _, _, _, expected_micros)) 303 .WillOnce(Return(0)); 304 EXPECT_CALL(mock_alsa_wrapper_, PcmGetParams(_, _, _)) 305 .WillOnce(DoAll(SetArgumentPointee<1>(kTestFramesPerPacket), 306 SetArgumentPointee<2>(kTestFramesPerPacket / 2), 307 Return(0))); 308 309 test_stream = CreateStream(kTestChannelLayout, 310 kOverMinLatencyPacketSize); 311 ASSERT_TRUE(test_stream->Open()); 312 313 // Now close it and test that everything was released. 314 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle)) 315 .WillOnce(Return(0)); 316 EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle)) 317 .WillOnce(Return(kTestDeviceName)); 318 test_stream->Close(); 319 320 Mock::VerifyAndClear(&mock_alsa_wrapper_); 321 Mock::VerifyAndClear(mock_manager_.get()); 322 } 323 324 TEST_F(AlsaPcmOutputStreamTest, OpenClose) { 325 int64 expected_micros = AlsaPcmOutputStream::FramesToTimeDelta( 326 2 * kTestFramesPerPacket, kTestSampleRate).InMicroseconds(); 327 328 // Open() call opens the playback device, sets the parameters, posts a task 329 // with the resulting configuration data, and transitions the object state to 330 // kIsOpened. 331 EXPECT_CALL(mock_alsa_wrapper_, 332 PcmOpen(_, StrEq(kTestDeviceName), 333 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) 334 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), 335 Return(0))); 336 EXPECT_CALL(mock_alsa_wrapper_, 337 PcmSetParams(kFakeHandle, 338 SND_PCM_FORMAT_U8, 339 SND_PCM_ACCESS_RW_INTERLEAVED, 340 ChannelLayoutToChannelCount(kTestChannelLayout), 341 kTestSampleRate, 342 1, 343 expected_micros)) 344 .WillOnce(Return(0)); 345 EXPECT_CALL(mock_alsa_wrapper_, PcmGetParams(kFakeHandle, _, _)) 346 .WillOnce(DoAll(SetArgumentPointee<1>(kTestFramesPerPacket), 347 SetArgumentPointee<2>(kTestFramesPerPacket / 2), 348 Return(0))); 349 350 // Open the stream. 351 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); 352 ASSERT_TRUE(test_stream->Open()); 353 354 EXPECT_EQ(AlsaPcmOutputStream::kIsOpened, test_stream->state()); 355 EXPECT_EQ(kFakeHandle, test_stream->playback_handle_); 356 EXPECT_EQ(kTestFramesPerPacket, test_stream->frames_per_packet_); 357 EXPECT_TRUE(test_stream->buffer_.get()); 358 EXPECT_FALSE(test_stream->stop_stream_); 359 360 // Now close it and test that everything was released. 361 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle)) 362 .WillOnce(Return(0)); 363 EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle)) 364 .WillOnce(Return(kTestDeviceName)); 365 test_stream->Close(); 366 } 367 368 TEST_F(AlsaPcmOutputStreamTest, PcmOpenFailed) { 369 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _)) 370 .WillOnce(Return(kTestFailedErrno)); 371 EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno)) 372 .WillOnce(Return(kDummyMessage)); 373 374 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); 375 ASSERT_FALSE(test_stream->Open()); 376 ASSERT_EQ(AlsaPcmOutputStream::kInError, test_stream->state()); 377 378 // Ensure internal state is set for a no-op stream if PcmOpen() failes. 379 EXPECT_TRUE(test_stream->stop_stream_); 380 EXPECT_TRUE(test_stream->playback_handle_ == NULL); 381 EXPECT_FALSE(test_stream->buffer_.get()); 382 383 // Close the stream since we opened it to make destruction happy. 384 test_stream->Close(); 385 } 386 387 TEST_F(AlsaPcmOutputStreamTest, PcmSetParamsFailed) { 388 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _)) 389 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), 390 Return(0))); 391 EXPECT_CALL(mock_alsa_wrapper_, PcmSetParams(_, _, _, _, _, _, _)) 392 .WillOnce(Return(kTestFailedErrno)); 393 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle)) 394 .WillOnce(Return(0)); 395 EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle)) 396 .WillOnce(Return(kTestDeviceName)); 397 EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno)) 398 .WillOnce(Return(kDummyMessage)); 399 400 // If open fails, the stream stays in kCreated because it has effectively had 401 // no changes. 402 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); 403 ASSERT_FALSE(test_stream->Open()); 404 EXPECT_EQ(AlsaPcmOutputStream::kInError, test_stream->state()); 405 406 // Ensure internal state is set for a no-op stream if PcmSetParams() failes. 407 EXPECT_TRUE(test_stream->stop_stream_); 408 EXPECT_TRUE(test_stream->playback_handle_ == NULL); 409 EXPECT_FALSE(test_stream->buffer_.get()); 410 411 // Close the stream since we opened it to make destruction happy. 412 test_stream->Close(); 413 } 414 415 TEST_F(AlsaPcmOutputStreamTest, StartStop) { 416 // Open() call opens the playback device, sets the parameters, posts a task 417 // with the resulting configuration data, and transitions the object state to 418 // kIsOpened. 419 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _)) 420 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), 421 Return(0))); 422 EXPECT_CALL(mock_alsa_wrapper_, PcmSetParams(_, _, _, _, _, _, _)) 423 .WillOnce(Return(0)); 424 EXPECT_CALL(mock_alsa_wrapper_, PcmGetParams(_, _, _)) 425 .WillOnce(DoAll(SetArgumentPointee<1>(kTestFramesPerPacket), 426 SetArgumentPointee<2>(kTestFramesPerPacket / 2), 427 Return(0))); 428 429 // Open the stream. 430 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); 431 ASSERT_TRUE(test_stream->Open()); 432 433 // Expect Device setup. 434 EXPECT_CALL(mock_alsa_wrapper_, PcmDrop(kFakeHandle)) 435 .WillOnce(Return(0)); 436 EXPECT_CALL(mock_alsa_wrapper_, PcmPrepare(kFakeHandle)) 437 .WillOnce(Return(0)); 438 439 // Expect the pre-roll. 440 MockAudioSourceCallback mock_callback; 441 EXPECT_CALL(mock_alsa_wrapper_, PcmState(kFakeHandle)) 442 .WillRepeatedly(Return(SND_PCM_STATE_RUNNING)); 443 EXPECT_CALL(mock_alsa_wrapper_, PcmDelay(kFakeHandle, _)) 444 .WillRepeatedly(DoAll(SetArgumentPointee<1>(0), Return(0))); 445 EXPECT_CALL(mock_callback, OnMoreData(_, _)) 446 .WillRepeatedly(DoAll(ClearBuffer(), Return(kTestFramesPerPacket))); 447 EXPECT_CALL(mock_alsa_wrapper_, PcmWritei(kFakeHandle, _, _)) 448 .WillRepeatedly(Return(kTestFramesPerPacket)); 449 450 // Expect scheduling. 451 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(kFakeHandle)) 452 .Times(AtLeast(2)) 453 .WillRepeatedly(Return(kTestFramesPerPacket)); 454 455 test_stream->Start(&mock_callback); 456 // Start() will issue a WriteTask() directly and then schedule the next one, 457 // call Stop() immediately after to ensure we don't run the message loop 458 // forever. 459 test_stream->Stop(); 460 message_loop_.RunUntilIdle(); 461 462 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle)) 463 .WillOnce(Return(0)); 464 EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle)) 465 .WillOnce(Return(kTestDeviceName)); 466 test_stream->Close(); 467 } 468 469 TEST_F(AlsaPcmOutputStreamTest, WritePacket_FinishedPacket) { 470 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); 471 InitBuffer(test_stream); 472 test_stream->TransitionTo(AlsaPcmOutputStream::kIsOpened); 473 test_stream->TransitionTo(AlsaPcmOutputStream::kIsPlaying); 474 475 // Nothing should happen. Don't set any expectations and Our strict mocks 476 // should verify most of this. 477 478 // Test empty buffer. 479 test_stream->buffer_->Clear(); 480 test_stream->WritePacket(); 481 test_stream->Close(); 482 } 483 484 TEST_F(AlsaPcmOutputStreamTest, WritePacket_NormalPacket) { 485 // We need to open the stream before writing data to ALSA. 486 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _)) 487 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), 488 Return(0))); 489 EXPECT_CALL(mock_alsa_wrapper_, PcmSetParams(_, _, _, _, _, _, _)) 490 .WillOnce(Return(0)); 491 EXPECT_CALL(mock_alsa_wrapper_, PcmGetParams(_, _, _)) 492 .WillOnce(DoAll(SetArgumentPointee<1>(kTestFramesPerPacket), 493 SetArgumentPointee<2>(kTestFramesPerPacket / 2), 494 Return(0))); 495 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); 496 ASSERT_TRUE(test_stream->Open()); 497 InitBuffer(test_stream); 498 test_stream->TransitionTo(AlsaPcmOutputStream::kIsPlaying); 499 500 // Write a little less than half the data. 501 int written = packet_->data_size() / kTestBytesPerFrame / 2 - 1; 502 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(kFakeHandle)) 503 .WillOnce(Return(written)); 504 EXPECT_CALL(mock_alsa_wrapper_, PcmWritei(kFakeHandle, packet_->data(), _)) 505 .WillOnce(Return(written)); 506 507 test_stream->WritePacket(); 508 509 ASSERT_EQ(test_stream->buffer_->forward_bytes(), 510 packet_->data_size() - written * kTestBytesPerFrame); 511 512 // Write the rest. 513 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(kFakeHandle)) 514 .WillOnce(Return(kTestFramesPerPacket - written)); 515 EXPECT_CALL(mock_alsa_wrapper_, 516 PcmWritei(kFakeHandle, 517 packet_->data() + written * kTestBytesPerFrame, 518 _)) 519 .WillOnce(Return(packet_->data_size() / kTestBytesPerFrame - written)); 520 test_stream->WritePacket(); 521 EXPECT_EQ(0, test_stream->buffer_->forward_bytes()); 522 523 // Now close it and test that everything was released. 524 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle)) 525 .WillOnce(Return(0)); 526 EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle)) 527 .WillOnce(Return(kTestDeviceName)); 528 test_stream->Close(); 529 } 530 531 TEST_F(AlsaPcmOutputStreamTest, WritePacket_WriteFails) { 532 // We need to open the stream before writing data to ALSA. 533 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _)) 534 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), 535 Return(0))); 536 EXPECT_CALL(mock_alsa_wrapper_, PcmSetParams(_, _, _, _, _, _, _)) 537 .WillOnce(Return(0)); 538 EXPECT_CALL(mock_alsa_wrapper_, PcmGetParams(_, _, _)) 539 .WillOnce(DoAll(SetArgumentPointee<1>(kTestFramesPerPacket), 540 SetArgumentPointee<2>(kTestFramesPerPacket / 2), 541 Return(0))); 542 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); 543 ASSERT_TRUE(test_stream->Open()); 544 InitBuffer(test_stream); 545 test_stream->TransitionTo(AlsaPcmOutputStream::kIsPlaying); 546 547 // Fail due to a recoverable error and see that PcmRecover code path 548 // continues normally. 549 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(kFakeHandle)) 550 .WillOnce(Return(kTestFramesPerPacket)); 551 EXPECT_CALL(mock_alsa_wrapper_, PcmWritei(kFakeHandle, _, _)) 552 .WillOnce(Return(-EINTR)); 553 EXPECT_CALL(mock_alsa_wrapper_, PcmRecover(kFakeHandle, _, _)) 554 .WillOnce(Return(0)); 555 556 test_stream->WritePacket(); 557 558 ASSERT_EQ(test_stream->buffer_->forward_bytes(), packet_->data_size()); 559 560 // Fail the next write, and see that stop_stream_ is set. 561 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(kFakeHandle)) 562 .WillOnce(Return(kTestFramesPerPacket)); 563 EXPECT_CALL(mock_alsa_wrapper_, PcmWritei(kFakeHandle, _, _)) 564 .WillOnce(Return(kTestFailedErrno)); 565 EXPECT_CALL(mock_alsa_wrapper_, PcmRecover(kFakeHandle, _, _)) 566 .WillOnce(Return(kTestFailedErrno)); 567 EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno)) 568 .WillOnce(Return(kDummyMessage)); 569 test_stream->WritePacket(); 570 EXPECT_EQ(test_stream->buffer_->forward_bytes(), packet_->data_size()); 571 EXPECT_TRUE(test_stream->stop_stream_); 572 573 // Now close it and test that everything was released. 574 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle)) 575 .WillOnce(Return(0)); 576 EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle)) 577 .WillOnce(Return(kTestDeviceName)); 578 test_stream->Close(); 579 } 580 581 TEST_F(AlsaPcmOutputStreamTest, WritePacket_StopStream) { 582 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); 583 InitBuffer(test_stream); 584 test_stream->TransitionTo(AlsaPcmOutputStream::kIsOpened); 585 test_stream->TransitionTo(AlsaPcmOutputStream::kIsPlaying); 586 587 // No expectations set on the strict mock because nothing should be called. 588 test_stream->stop_stream_ = true; 589 test_stream->WritePacket(); 590 EXPECT_EQ(0, test_stream->buffer_->forward_bytes()); 591 test_stream->Close(); 592 } 593 594 TEST_F(AlsaPcmOutputStreamTest, BufferPacket) { 595 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); 596 InitBuffer(test_stream); 597 test_stream->buffer_->Clear(); 598 599 MockAudioSourceCallback mock_callback; 600 EXPECT_CALL(mock_alsa_wrapper_, PcmState(_)) 601 .WillOnce(Return(SND_PCM_STATE_RUNNING)); 602 EXPECT_CALL(mock_alsa_wrapper_, PcmDelay(_, _)) 603 .WillOnce(DoAll(SetArgumentPointee<1>(1), Return(0))); 604 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(_)) 605 .WillRepeatedly(Return(0)); // Buffer is full. 606 607 // Return a partially filled packet. 608 EXPECT_CALL(mock_callback, OnMoreData(_, _)) 609 .WillOnce(DoAll(ClearBuffer(), Return(kTestFramesPerPacket / 2))); 610 611 bool source_exhausted; 612 test_stream->set_source_callback(&mock_callback); 613 test_stream->packet_size_ = kTestPacketSize; 614 test_stream->BufferPacket(&source_exhausted); 615 616 EXPECT_EQ(kTestPacketSize / 2, test_stream->buffer_->forward_bytes()); 617 EXPECT_FALSE(source_exhausted); 618 test_stream->Close(); 619 } 620 621 TEST_F(AlsaPcmOutputStreamTest, BufferPacket_Negative) { 622 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); 623 InitBuffer(test_stream); 624 test_stream->buffer_->Clear(); 625 626 // Simulate where the underrun has occurred right after checking the delay. 627 MockAudioSourceCallback mock_callback; 628 EXPECT_CALL(mock_alsa_wrapper_, PcmState(_)) 629 .WillOnce(Return(SND_PCM_STATE_RUNNING)); 630 EXPECT_CALL(mock_alsa_wrapper_, PcmDelay(_, _)) 631 .WillOnce(DoAll(SetArgumentPointee<1>(-1), Return(0))); 632 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(_)) 633 .WillRepeatedly(Return(0)); // Buffer is full. 634 EXPECT_CALL(mock_callback, OnMoreData(_, _)) 635 .WillOnce(DoAll(ClearBuffer(), Return(kTestFramesPerPacket / 2))); 636 637 bool source_exhausted; 638 test_stream->set_source_callback(&mock_callback); 639 test_stream->packet_size_ = kTestPacketSize; 640 test_stream->BufferPacket(&source_exhausted); 641 642 EXPECT_EQ(kTestPacketSize / 2, test_stream->buffer_->forward_bytes()); 643 EXPECT_FALSE(source_exhausted); 644 test_stream->Close(); 645 } 646 647 TEST_F(AlsaPcmOutputStreamTest, BufferPacket_Underrun) { 648 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); 649 InitBuffer(test_stream); 650 test_stream->buffer_->Clear(); 651 652 // If ALSA has underrun then we should assume a delay of zero. 653 MockAudioSourceCallback mock_callback; 654 EXPECT_CALL(mock_alsa_wrapper_, PcmState(_)) 655 .WillOnce(Return(SND_PCM_STATE_XRUN)); 656 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(_)) 657 .WillRepeatedly(Return(0)); // Buffer is full. 658 EXPECT_CALL(mock_callback, 659 OnMoreData(_, AllOf( 660 Field(&AudioBuffersState::pending_bytes, 0), 661 Field(&AudioBuffersState::hardware_delay_bytes, 0)))) 662 .WillOnce(DoAll(ClearBuffer(), Return(kTestFramesPerPacket / 2))); 663 664 bool source_exhausted; 665 test_stream->set_source_callback(&mock_callback); 666 test_stream->packet_size_ = kTestPacketSize; 667 test_stream->BufferPacket(&source_exhausted); 668 669 EXPECT_EQ(kTestPacketSize / 2, test_stream->buffer_->forward_bytes()); 670 EXPECT_FALSE(source_exhausted); 671 test_stream->Close(); 672 } 673 674 TEST_F(AlsaPcmOutputStreamTest, BufferPacket_FullBuffer) { 675 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); 676 InitBuffer(test_stream); 677 // No expectations set on the strict mock because nothing should be called. 678 bool source_exhausted; 679 test_stream->packet_size_ = kTestPacketSize; 680 test_stream->BufferPacket(&source_exhausted); 681 EXPECT_EQ(kTestPacketSize, test_stream->buffer_->forward_bytes()); 682 EXPECT_FALSE(source_exhausted); 683 test_stream->Close(); 684 } 685 686 TEST_F(AlsaPcmOutputStreamTest, AutoSelectDevice_DeviceSelect) { 687 // Try channels from 1 -> 9. and see that we get the more specific surroundXX 688 // device opened for channels 4-8. For all other channels, the device should 689 // default to |AlsaPcmOutputStream::kDefaultDevice|. We should also not 690 // downmix any channel in this case because downmixing is only defined for 691 // channels 4-8, which we are guaranteeing to work. 692 // 693 // Note that the loop starts at "1", so the first parameter is ignored in 694 // these arrays. 695 const char* kExpectedDeviceName[] = { NULL, 696 AlsaPcmOutputStream::kDefaultDevice, 697 AlsaPcmOutputStream::kDefaultDevice, 698 AlsaPcmOutputStream::kDefaultDevice, 699 kSurround40, kSurround50, kSurround51, 700 kSurround70, kSurround71, 701 AlsaPcmOutputStream::kDefaultDevice }; 702 bool kExpectedDownmix[] = { false, false, false, false, false, true, 703 false, false, false, false }; 704 ChannelLayout kExpectedLayouts[] = { CHANNEL_LAYOUT_NONE, 705 CHANNEL_LAYOUT_MONO, 706 CHANNEL_LAYOUT_STEREO, 707 CHANNEL_LAYOUT_SURROUND, 708 CHANNEL_LAYOUT_4_0, 709 CHANNEL_LAYOUT_5_0, 710 CHANNEL_LAYOUT_5_1, 711 CHANNEL_LAYOUT_7_0, 712 CHANNEL_LAYOUT_7_1 }; 713 714 715 for (int i = 1; i < 9; ++i) { 716 if (i == 3 || i == 4 || i == 5) // invalid number of channels 717 continue; 718 SCOPED_TRACE(base::StringPrintf("Attempting %d Channel", i)); 719 720 // Hints will only be grabbed for channel numbers that have non-default 721 // devices associated with them. 722 if (kExpectedDeviceName[i] != AlsaPcmOutputStream::kDefaultDevice) { 723 // The DeviceNameHint and DeviceNameFreeHint need to be paired to avoid a 724 // memory leak. 725 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameHint(_, _, _)) 726 .WillOnce(DoAll(SetArgumentPointee<2>(&kFakeHints[0]), Return(0))); 727 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameFreeHint(&kFakeHints[0])) 728 .Times(1); 729 } 730 731 EXPECT_CALL(mock_alsa_wrapper_, 732 PcmOpen(_, StrEq(kExpectedDeviceName[i]), _, _)) 733 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), Return(0))); 734 EXPECT_CALL(mock_alsa_wrapper_, 735 PcmSetParams(kFakeHandle, _, _, i, _, _, _)) 736 .WillOnce(Return(0)); 737 738 // The parameters are specified by ALSA documentation, and are in constants 739 // in the implementation files. 740 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameGetHint(_, StrEq("IOID"))) 741 .WillRepeatedly(Invoke(OutputHint)); 742 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameGetHint(_, StrEq("NAME"))) 743 .WillRepeatedly(Invoke(EchoHint)); 744 745 AlsaPcmOutputStream* test_stream = CreateStream(kExpectedLayouts[i]); 746 EXPECT_TRUE(test_stream->AutoSelectDevice(i)); 747 EXPECT_EQ(kExpectedDownmix[i], 748 static_cast<bool>(test_stream->channel_mixer_)); 749 750 Mock::VerifyAndClearExpectations(&mock_alsa_wrapper_); 751 Mock::VerifyAndClearExpectations(mock_manager_.get()); 752 test_stream->Close(); 753 } 754 } 755 756 TEST_F(AlsaPcmOutputStreamTest, AutoSelectDevice_FallbackDevices) { 757 using std::string; 758 759 // If there are problems opening a multi-channel device, it the fallbacks 760 // operations should be as follows. Assume the multi-channel device name is 761 // surround50: 762 // 763 // 1) Try open "surround50" 764 // 2) Try open "plug:surround50". 765 // 3) Try open "default". 766 // 4) Try open "plug:default". 767 // 5) Give up trying to open. 768 // 769 const string first_try = kSurround50; 770 const string second_try = string(AlsaPcmOutputStream::kPlugPrefix) + 771 kSurround50; 772 const string third_try = AlsaPcmOutputStream::kDefaultDevice; 773 const string fourth_try = string(AlsaPcmOutputStream::kPlugPrefix) + 774 AlsaPcmOutputStream::kDefaultDevice; 775 776 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameHint(_, _, _)) 777 .WillOnce(DoAll(SetArgumentPointee<2>(&kFakeHints[0]), Return(0))); 778 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameFreeHint(&kFakeHints[0])) 779 .Times(1); 780 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameGetHint(_, StrEq("IOID"))) 781 .WillRepeatedly(Invoke(OutputHint)); 782 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameGetHint(_, StrEq("NAME"))) 783 .WillRepeatedly(Invoke(EchoHint)); 784 EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno)) 785 .WillRepeatedly(Return(kDummyMessage)); 786 787 InSequence s; 788 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, StrEq(first_try.c_str()), _, _)) 789 .WillOnce(Return(kTestFailedErrno)); 790 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, StrEq(second_try.c_str()), _, _)) 791 .WillOnce(Return(kTestFailedErrno)); 792 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, StrEq(third_try.c_str()), _, _)) 793 .WillOnce(Return(kTestFailedErrno)); 794 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, StrEq(fourth_try.c_str()), _, _)) 795 .WillOnce(Return(kTestFailedErrno)); 796 797 AlsaPcmOutputStream* test_stream = CreateStream(CHANNEL_LAYOUT_5_0); 798 EXPECT_FALSE(test_stream->AutoSelectDevice(5)); 799 test_stream->Close(); 800 } 801 802 TEST_F(AlsaPcmOutputStreamTest, AutoSelectDevice_HintFail) { 803 // Should get |kDefaultDevice|, and force a 2-channel downmix on a failure to 804 // enumerate devices. 805 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameHint(_, _, _)) 806 .WillRepeatedly(Return(kTestFailedErrno)); 807 EXPECT_CALL(mock_alsa_wrapper_, 808 PcmOpen(_, StrEq(AlsaPcmOutputStream::kDefaultDevice), _, _)) 809 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), Return(0))); 810 EXPECT_CALL(mock_alsa_wrapper_, 811 PcmSetParams(kFakeHandle, _, _, 2, _, _, _)) 812 .WillOnce(Return(0)); 813 EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno)) 814 .WillOnce(Return(kDummyMessage)); 815 816 AlsaPcmOutputStream* test_stream = CreateStream(CHANNEL_LAYOUT_5_0); 817 EXPECT_TRUE(test_stream->AutoSelectDevice(5)); 818 EXPECT_TRUE(test_stream->channel_mixer_); 819 test_stream->Close(); 820 } 821 822 TEST_F(AlsaPcmOutputStreamTest, BufferPacket_StopStream) { 823 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); 824 InitBuffer(test_stream); 825 test_stream->stop_stream_ = true; 826 bool source_exhausted; 827 test_stream->BufferPacket(&source_exhausted); 828 EXPECT_EQ(0, test_stream->buffer_->forward_bytes()); 829 EXPECT_TRUE(source_exhausted); 830 test_stream->Close(); 831 } 832 833 TEST_F(AlsaPcmOutputStreamTest, ScheduleNextWrite) { 834 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); 835 test_stream->TransitionTo(AlsaPcmOutputStream::kIsOpened); 836 test_stream->TransitionTo(AlsaPcmOutputStream::kIsPlaying); 837 InitBuffer(test_stream); 838 DVLOG(1) << test_stream->state(); 839 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(_)) 840 .WillOnce(Return(10)); 841 test_stream->ScheduleNextWrite(false); 842 DVLOG(1) << test_stream->state(); 843 // TODO(sergeyu): Figure out how to check that the task has been added to the 844 // message loop. 845 846 // Cleanup the message queue. Currently ~MessageQueue() doesn't free pending 847 // tasks unless running on valgrind. The code below is needed to keep 848 // heapcheck happy. 849 850 test_stream->stop_stream_ = true; 851 DVLOG(1) << test_stream->state(); 852 test_stream->TransitionTo(AlsaPcmOutputStream::kIsClosed); 853 DVLOG(1) << test_stream->state(); 854 test_stream->Close(); 855 } 856 857 TEST_F(AlsaPcmOutputStreamTest, ScheduleNextWrite_StopStream) { 858 AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); 859 test_stream->TransitionTo(AlsaPcmOutputStream::kIsOpened); 860 test_stream->TransitionTo(AlsaPcmOutputStream::kIsPlaying); 861 862 InitBuffer(test_stream); 863 864 test_stream->stop_stream_ = true; 865 test_stream->ScheduleNextWrite(true); 866 867 // TODO(ajwong): Find a way to test whether or not another task has been 868 // posted so we can verify that the Alsa code will indeed break the task 869 // posting loop. 870 871 test_stream->TransitionTo(AlsaPcmOutputStream::kIsClosed); 872 test_stream->Close(); 873 } 874 875 } // namespace media 876