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