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