| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/logging.h" | 5 #include "base/logging.h" |
| 6 #include "base/string_util.h" |
| 6 #include "media/audio/linux/alsa_output.h" | 7 #include "media/audio/linux/alsa_output.h" |
| 7 #include "media/audio/linux/alsa_wrapper.h" | 8 #include "media/audio/linux/alsa_wrapper.h" |
| 8 #include "media/audio/linux/audio_manager_linux.h" | 9 #include "media/audio/linux/audio_manager_linux.h" |
| 9 #include "testing/gmock/include/gmock/gmock.h" | 10 #include "testing/gmock/include/gmock/gmock.h" |
| 10 #include "testing/gtest/include/gtest/gtest.h" | 11 #include "testing/gtest/include/gtest/gtest.h" |
| 11 | 12 |
| 12 using testing::_; | 13 using testing::_; |
| 13 using testing::DoAll; | 14 using testing::DoAll; |
| 14 using testing::Eq; | 15 using testing::Eq; |
| 16 using testing::InSequence; |
| 17 using testing::Invoke; |
| 18 using testing::Mock; |
| 19 using testing::MockFunction; |
| 15 using testing::Return; | 20 using testing::Return; |
| 16 using testing::SetArgumentPointee; | 21 using testing::SetArgumentPointee; |
| 17 using testing::StrictMock; | 22 using testing::StrictMock; |
| 18 using testing::StrEq; | 23 using testing::StrEq; |
| 24 using testing::Unused; |
| 19 | 25 |
| 20 class MockAlsaWrapper : public AlsaWrapper { | 26 class MockAlsaWrapper : public AlsaWrapper { |
| 21 public: | 27 public: |
| 28 MOCK_METHOD3(DeviceNameHint, int(int card, |
| 29 const char* iface, |
| 30 void*** hints)); |
| 31 MOCK_METHOD2(DeviceNameGetHint, char*(const void* hint, const char* id)); |
| 32 MOCK_METHOD1(DeviceNameFreeHint, int(void** hints)); |
| 33 |
| 22 MOCK_METHOD4(PcmOpen, int(snd_pcm_t** handle, const char* name, | 34 MOCK_METHOD4(PcmOpen, int(snd_pcm_t** handle, const char* name, |
| 23 snd_pcm_stream_t stream, int mode)); | 35 snd_pcm_stream_t stream, int mode)); |
| 24 MOCK_METHOD1(PcmClose, int(snd_pcm_t* handle)); | 36 MOCK_METHOD1(PcmClose, int(snd_pcm_t* handle)); |
| 25 MOCK_METHOD1(PcmPrepare, int(snd_pcm_t* handle)); | 37 MOCK_METHOD1(PcmPrepare, int(snd_pcm_t* handle)); |
| 26 MOCK_METHOD1(PcmDrop, int(snd_pcm_t* handle)); | 38 MOCK_METHOD1(PcmDrop, int(snd_pcm_t* handle)); |
| 27 MOCK_METHOD2(PcmDelay, int(snd_pcm_t* handle, snd_pcm_sframes_t* delay)); | 39 MOCK_METHOD2(PcmDelay, int(snd_pcm_t* handle, snd_pcm_sframes_t* delay)); |
| 28 MOCK_METHOD3(PcmWritei, snd_pcm_sframes_t(snd_pcm_t* handle, | 40 MOCK_METHOD3(PcmWritei, snd_pcm_sframes_t(snd_pcm_t* handle, |
| 29 const void* buffer, | 41 const void* buffer, |
| 30 snd_pcm_uframes_t size)); | 42 snd_pcm_uframes_t size)); |
| 31 MOCK_METHOD3(PcmRecover, int(snd_pcm_t* handle, int err, int silent)); | 43 MOCK_METHOD3(PcmRecover, int(snd_pcm_t* handle, int err, int silent)); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 57 MOCK_METHOD0(MuteAll, void()); | 69 MOCK_METHOD0(MuteAll, void()); |
| 58 MOCK_METHOD0(UnMuteAll, void()); | 70 MOCK_METHOD0(UnMuteAll, void()); |
| 59 | 71 |
| 60 MOCK_METHOD1(ReleaseStream, void(AlsaPcmOutputStream* stream)); | 72 MOCK_METHOD1(ReleaseStream, void(AlsaPcmOutputStream* stream)); |
| 61 }; | 73 }; |
| 62 | 74 |
| 63 class AlsaPcmOutputStreamTest : public testing::Test { | 75 class AlsaPcmOutputStreamTest : public testing::Test { |
| 64 protected: | 76 protected: |
| 65 AlsaPcmOutputStreamTest() | 77 AlsaPcmOutputStreamTest() |
| 66 : packet_(kTestPacketSize + 1) { | 78 : packet_(kTestPacketSize + 1) { |
| 67 test_stream_ = new AlsaPcmOutputStream(kTestDeviceName, | 79 test_stream_ = CreateStreamWithChannels(kTestChannels); |
| 68 kTestFormat, | |
| 69 kTestChannels, | |
| 70 kTestSampleRate, | |
| 71 kTestBitsPerSample, | |
| 72 &mock_alsa_wrapper_, | |
| 73 &mock_manager_, | |
| 74 &message_loop_); | |
| 75 | |
| 76 packet_.size = kTestPacketSize; | 80 packet_.size = kTestPacketSize; |
| 77 } | 81 } |
| 78 | 82 |
| 79 virtual ~AlsaPcmOutputStreamTest() { | 83 virtual ~AlsaPcmOutputStreamTest() { |
| 80 test_stream_ = NULL; | 84 test_stream_ = NULL; |
| 81 } | 85 } |
| 82 | 86 |
| 87 AlsaPcmOutputStream* CreateStreamWithChannels(int channels) { |
| 88 return new AlsaPcmOutputStream(kTestDeviceName, |
| 89 kTestFormat, |
| 90 channels, |
| 91 kTestSampleRate, |
| 92 kTestBitsPerSample, |
| 93 &mock_alsa_wrapper_, |
| 94 &mock_manager_, |
| 95 &message_loop_); |
| 96 } |
| 97 |
| 98 // Helper function to malloc the string returned by DeviceNameHint for NAME. |
| 99 static char* EchoHint(const void* name, Unused) { |
| 100 return strdup(static_cast<const char*>(name)); |
| 101 } |
| 102 |
| 103 // Helper function to malloc the string returned by DeviceNameHint for IOID. |
| 104 static char* OutputHint(Unused, Unused) { |
| 105 return strdup("Output"); |
| 106 } |
| 107 |
| 83 static const int kTestChannels; | 108 static const int kTestChannels; |
| 84 static const int kTestSampleRate; | 109 static const int kTestSampleRate; |
| 85 static const int kTestBitsPerSample; | 110 static const int kTestBitsPerSample; |
| 86 static const int kTestBytesPerFrame; | 111 static const int kTestBytesPerFrame; |
| 87 static const AudioManager::Format kTestFormat; | 112 static const AudioManager::Format kTestFormat; |
| 88 static const char kTestDeviceName[]; | 113 static const char kTestDeviceName[]; |
| 89 static const char kDummyMessage[]; | 114 static const char kDummyMessage[]; |
| 90 static const int kTestFramesPerPacket; | 115 static const int kTestFramesPerPacket; |
| 91 static const size_t kTestPacketSize; | 116 static const size_t kTestPacketSize; |
| 92 static const int kTestFailedErrno; | 117 static const int kTestFailedErrno; |
| 93 static snd_pcm_t* const kFakeHandle; | 118 static snd_pcm_t* const kFakeHandle; |
| 94 | 119 |
| 120 // Used to simulate DeviceNameHint. |
| 121 static char kSurround40[]; |
| 122 static char kSurround41[]; |
| 123 static char kSurround50[]; |
| 124 static char kSurround51[]; |
| 125 static char kSurround70[]; |
| 126 static char kSurround71[]; |
| 127 static void* kFakeHints[]; |
| 128 |
| 95 StrictMock<MockAlsaWrapper> mock_alsa_wrapper_; | 129 StrictMock<MockAlsaWrapper> mock_alsa_wrapper_; |
| 96 StrictMock<MockAudioManagerLinux> mock_manager_; | 130 StrictMock<MockAudioManagerLinux> mock_manager_; |
| 97 MessageLoop message_loop_; | 131 MessageLoop message_loop_; |
| 98 scoped_refptr<AlsaPcmOutputStream> test_stream_; | 132 scoped_refptr<AlsaPcmOutputStream> test_stream_; |
| 99 AlsaPcmOutputStream::Packet packet_; | 133 AlsaPcmOutputStream::Packet packet_; |
| 100 | 134 |
| 101 private: | 135 private: |
| 102 DISALLOW_COPY_AND_ASSIGN(AlsaPcmOutputStreamTest); | 136 DISALLOW_COPY_AND_ASSIGN(AlsaPcmOutputStreamTest); |
| 103 }; | 137 }; |
| 104 | 138 |
| 105 const int AlsaPcmOutputStreamTest::kTestChannels = 2; | 139 const int AlsaPcmOutputStreamTest::kTestChannels = 2; |
| 106 const int AlsaPcmOutputStreamTest::kTestSampleRate = | 140 const int AlsaPcmOutputStreamTest::kTestSampleRate = |
| 107 AudioManager::kAudioCDSampleRate; | 141 AudioManager::kAudioCDSampleRate; |
| 108 const int AlsaPcmOutputStreamTest::kTestBitsPerSample = 8; | 142 const int AlsaPcmOutputStreamTest::kTestBitsPerSample = 8; |
| 109 const int AlsaPcmOutputStreamTest::kTestBytesPerFrame = | 143 const int AlsaPcmOutputStreamTest::kTestBytesPerFrame = |
| 110 AlsaPcmOutputStreamTest::kTestBitsPerSample / 8 * | 144 AlsaPcmOutputStreamTest::kTestBitsPerSample / 8 * |
| 111 AlsaPcmOutputStreamTest::kTestChannels; | 145 AlsaPcmOutputStreamTest::kTestChannels; |
| 112 const AudioManager::Format AlsaPcmOutputStreamTest::kTestFormat = | 146 const AudioManager::Format AlsaPcmOutputStreamTest::kTestFormat = |
| 113 AudioManager::AUDIO_PCM_LINEAR; | 147 AudioManager::AUDIO_PCM_LINEAR; |
| 114 const char AlsaPcmOutputStreamTest::kTestDeviceName[] = "TestDevice"; | 148 const char AlsaPcmOutputStreamTest::kTestDeviceName[] = "TestDevice"; |
| 115 const char AlsaPcmOutputStreamTest::kDummyMessage[] = "dummy"; | 149 const char AlsaPcmOutputStreamTest::kDummyMessage[] = "dummy"; |
| 116 const int AlsaPcmOutputStreamTest::kTestFramesPerPacket = 100; | 150 const int AlsaPcmOutputStreamTest::kTestFramesPerPacket = 1000; |
| 117 const size_t AlsaPcmOutputStreamTest::kTestPacketSize = | 151 const size_t AlsaPcmOutputStreamTest::kTestPacketSize = |
| 118 AlsaPcmOutputStreamTest::kTestFramesPerPacket * | 152 AlsaPcmOutputStreamTest::kTestFramesPerPacket * |
| 119 AlsaPcmOutputStreamTest::kTestBytesPerFrame; | 153 AlsaPcmOutputStreamTest::kTestBytesPerFrame; |
| 120 const int AlsaPcmOutputStreamTest::kTestFailedErrno = -EACCES; | 154 const int AlsaPcmOutputStreamTest::kTestFailedErrno = -EACCES; |
| 121 snd_pcm_t* const AlsaPcmOutputStreamTest::kFakeHandle = | 155 snd_pcm_t* const AlsaPcmOutputStreamTest::kFakeHandle = |
| 122 reinterpret_cast<snd_pcm_t*>(1); | 156 reinterpret_cast<snd_pcm_t*>(1); |
| 123 | 157 |
| 158 char AlsaPcmOutputStreamTest::kSurround40[] = "surround40:CARD=foo,DEV=0"; |
| 159 char AlsaPcmOutputStreamTest::kSurround41[] = "surround41:CARD=foo,DEV=0"; |
| 160 char AlsaPcmOutputStreamTest::kSurround50[] = "surround50:CARD=foo,DEV=0"; |
| 161 char AlsaPcmOutputStreamTest::kSurround51[] = "surround51:CARD=foo,DEV=0"; |
| 162 char AlsaPcmOutputStreamTest::kSurround70[] = "surround70:CARD=foo,DEV=0"; |
| 163 char AlsaPcmOutputStreamTest::kSurround71[] = "surround71:CARD=foo,DEV=0"; |
| 164 void* AlsaPcmOutputStreamTest::kFakeHints[] = { |
| 165 kSurround40, kSurround41, kSurround50, kSurround51, |
| 166 kSurround70, kSurround71, NULL }; |
| 167 |
| 124 TEST_F(AlsaPcmOutputStreamTest, ConstructedState) { | 168 TEST_F(AlsaPcmOutputStreamTest, ConstructedState) { |
| 125 EXPECT_EQ(AlsaPcmOutputStream::kCreated, | 169 EXPECT_EQ(AlsaPcmOutputStream::kCreated, |
| 126 test_stream_->shared_data_.state()); | 170 test_stream_->shared_data_.state()); |
| 127 | 171 |
| 128 // Should support mono. | 172 // Should support mono. |
| 129 test_stream_ = new AlsaPcmOutputStream(kTestDeviceName, | 173 test_stream_ = CreateStreamWithChannels(1); |
| 130 kTestFormat, | |
| 131 1, // Channels. | |
| 132 kTestSampleRate, | |
| 133 kTestBitsPerSample, | |
| 134 &mock_alsa_wrapper_, | |
| 135 &mock_manager_, | |
| 136 &message_loop_); | |
| 137 EXPECT_EQ(AlsaPcmOutputStream::kCreated, | 174 EXPECT_EQ(AlsaPcmOutputStream::kCreated, |
| 138 test_stream_->shared_data_.state()); | 175 test_stream_->shared_data_.state()); |
| 139 | 176 |
| 140 // Should not support multi-channel. | 177 // Should support multi-channel. |
| 141 test_stream_ = new AlsaPcmOutputStream(kTestDeviceName, | 178 test_stream_ = CreateStreamWithChannels(3); |
| 142 kTestFormat, | 179 EXPECT_EQ(AlsaPcmOutputStream::kCreated, |
| 143 3, // Channels. | |
| 144 kTestSampleRate, | |
| 145 kTestBitsPerSample, | |
| 146 &mock_alsa_wrapper_, | |
| 147 &mock_manager_, | |
| 148 &message_loop_); | |
| 149 EXPECT_EQ(AlsaPcmOutputStream::kInError, | |
| 150 test_stream_->shared_data_.state()); | 180 test_stream_->shared_data_.state()); |
| 151 | 181 |
| 152 // Bad bits per sample. | 182 // Bad bits per sample. |
| 153 test_stream_ = new AlsaPcmOutputStream(kTestDeviceName, | 183 test_stream_ = new AlsaPcmOutputStream(kTestDeviceName, |
| 154 kTestFormat, | 184 kTestFormat, |
| 155 kTestChannels, | 185 kTestChannels, |
| 156 kTestSampleRate, | 186 kTestSampleRate, |
| 157 kTestBitsPerSample - 1, | 187 kTestBitsPerSample - 1, |
| 158 &mock_alsa_wrapper_, | 188 &mock_alsa_wrapper_, |
| 159 &mock_manager_, | 189 &mock_manager_, |
| 160 &message_loop_); | 190 &message_loop_); |
| 161 EXPECT_EQ(AlsaPcmOutputStream::kInError, | 191 EXPECT_EQ(AlsaPcmOutputStream::kInError, |
| 162 test_stream_->shared_data_.state()); | 192 test_stream_->shared_data_.state()); |
| 163 | 193 |
| 164 // Bad format. | 194 // Bad format. |
| 165 test_stream_ = new AlsaPcmOutputStream(kTestDeviceName, | 195 test_stream_ = new AlsaPcmOutputStream(kTestDeviceName, |
| 166 AudioManager::AUDIO_PCM_DELTA, | 196 AudioManager::AUDIO_PCM_DELTA, |
| 167 kTestChannels, | 197 kTestChannels, |
| 168 kTestSampleRate, | 198 kTestSampleRate, |
| 169 kTestBitsPerSample, | 199 kTestBitsPerSample, |
| 170 &mock_alsa_wrapper_, | 200 &mock_alsa_wrapper_, |
| 171 &mock_manager_, | 201 &mock_manager_, |
| 172 &message_loop_); | 202 &message_loop_); |
| 173 EXPECT_EQ(AlsaPcmOutputStream::kInError, | 203 EXPECT_EQ(AlsaPcmOutputStream::kInError, |
| 174 test_stream_->shared_data_.state()); | 204 test_stream_->shared_data_.state()); |
| 175 } | 205 } |
| 176 | 206 |
| 207 TEST_F(AlsaPcmOutputStreamTest, LatencyFloor) { |
| 208 const double kMicrosPerFrame = |
| 209 static_cast<double>(1000000) / kTestSampleRate; |
| 210 const double kPacketFramesInMinLatency = |
| 211 AlsaPcmOutputStream::kMinLatencyMicros / kMicrosPerFrame / 2.0; |
| 212 const int kMinLatencyPacketSize = |
| 213 static_cast<int>(kPacketFramesInMinLatency * kTestBytesPerFrame); |
| 214 |
| 215 // Test that packets which would cause a latency under less than |
| 216 // AlsaPcmOutputStream::kMinLatencyMicros will get clipped to |
| 217 // AlsaPcmOutputStream::kMinLatencyMicros, |
| 218 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _)) |
| 219 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), |
| 220 Return(0))); |
| 221 EXPECT_CALL(mock_alsa_wrapper_, |
| 222 PcmSetParams(_, _, _, _, _, _, |
| 223 AlsaPcmOutputStream::kMinLatencyMicros)) |
| 224 .WillOnce(Return(0)); |
| 225 |
| 226 ASSERT_TRUE(test_stream_->Open(kMinLatencyPacketSize)); |
| 227 message_loop_.RunAllPending(); |
| 228 |
| 229 // Now close it and test that everything was released. |
| 230 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle)) .WillOnce(Return(0)); |
| 231 EXPECT_CALL(mock_manager_, ReleaseStream(test_stream_.get())); |
| 232 test_stream_->Close(); |
| 233 message_loop_.RunAllPending(); |
| 234 |
| 235 Mock::VerifyAndClear(&mock_alsa_wrapper_); |
| 236 Mock::VerifyAndClear(&mock_manager_); |
| 237 |
| 238 // Test that having more packets ends up with a latency based on packet size. |
| 239 const int kOverMinLatencyPacketSize = |
| 240 (kPacketFramesInMinLatency + 1) * kTestBytesPerFrame; |
| 241 int64 expected_micros = 2 * |
| 242 AlsaPcmOutputStream::FramesToMicros( |
| 243 kOverMinLatencyPacketSize / kTestBytesPerFrame, |
| 244 kTestSampleRate); |
| 245 |
| 246 // Recreate the stream to reset the state. |
| 247 test_stream_ = CreateStreamWithChannels(kTestChannels); |
| 248 |
| 249 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _)) |
| 250 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), Return(0))); |
| 251 EXPECT_CALL(mock_alsa_wrapper_, |
| 252 PcmSetParams(_, _, _, _, _, _, expected_micros)) |
| 253 .WillOnce(Return(0)); |
| 254 |
| 255 ASSERT_TRUE(test_stream_->Open(kOverMinLatencyPacketSize)); |
| 256 message_loop_.RunAllPending(); |
| 257 |
| 258 // Now close it and test that everything was released. |
| 259 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle)) |
| 260 .WillOnce(Return(0)); |
| 261 EXPECT_CALL(mock_manager_, ReleaseStream(test_stream_.get())); |
| 262 test_stream_->Close(); |
| 263 message_loop_.RunAllPending(); |
| 264 |
| 265 Mock::VerifyAndClear(&mock_alsa_wrapper_); |
| 266 Mock::VerifyAndClear(&mock_manager_); |
| 267 } |
| 268 |
| 177 TEST_F(AlsaPcmOutputStreamTest, OpenClose) { | 269 TEST_F(AlsaPcmOutputStreamTest, OpenClose) { |
| 178 int64 expected_micros = 2 * | 270 int64 expected_micros = 2 * |
| 179 AlsaPcmOutputStream::FramesToMicros(kTestPacketSize / kTestBytesPerFrame, | 271 AlsaPcmOutputStream::FramesToMicros(kTestPacketSize / kTestBytesPerFrame, |
| 180 kTestSampleRate); | 272 kTestSampleRate); |
| 181 | 273 |
| 182 // Open() call opens the playback device, sets the parameters, posts a task | 274 // Open() call opens the playback device, sets the parameters, posts a task |
| 183 // with the resulting configuration data, and transitions the object state to | 275 // with the resulting configuration data, and transitions the object state to |
| 184 // kIsOpened. | 276 // kIsOpened. |
| 185 EXPECT_CALL(mock_alsa_wrapper_, | 277 EXPECT_CALL(mock_alsa_wrapper_, |
| 186 PcmOpen(_, StrEq(kTestDeviceName), | 278 PcmOpen(_, StrEq(kTestDeviceName), |
| 187 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) | 279 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) |
| 188 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), | 280 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), |
| 189 Return(0))); | 281 Return(0))); |
| 190 EXPECT_CALL(mock_alsa_wrapper_, | 282 EXPECT_CALL(mock_alsa_wrapper_, |
| 191 PcmSetParams(kFakeHandle, | 283 PcmSetParams(kFakeHandle, |
| 192 SND_PCM_FORMAT_S8, | 284 SND_PCM_FORMAT_U8, |
| 193 SND_PCM_ACCESS_RW_INTERLEAVED, | 285 SND_PCM_ACCESS_RW_INTERLEAVED, |
| 194 kTestChannels, | 286 kTestChannels, |
| 195 kTestSampleRate, | 287 kTestSampleRate, |
| 196 1, | 288 1, |
| 197 expected_micros)) | 289 expected_micros)) |
| 198 .WillOnce(Return(0)); | 290 .WillOnce(Return(0)); |
| 199 | 291 |
| 200 // Open the stream. | 292 // Open the stream. |
| 201 ASSERT_TRUE(test_stream_->Open(kTestPacketSize)); | 293 ASSERT_TRUE(test_stream_->Open(kTestPacketSize)); |
| 202 message_loop_.RunAllPending(); | 294 message_loop_.RunAllPending(); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 219 EXPECT_FALSE(test_stream_->packet_.get()); | 311 EXPECT_FALSE(test_stream_->packet_.get()); |
| 220 EXPECT_TRUE(test_stream_->stop_stream_); | 312 EXPECT_TRUE(test_stream_->stop_stream_); |
| 221 } | 313 } |
| 222 | 314 |
| 223 TEST_F(AlsaPcmOutputStreamTest, PcmOpenFailed) { | 315 TEST_F(AlsaPcmOutputStreamTest, PcmOpenFailed) { |
| 224 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _)) | 316 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _)) |
| 225 .WillOnce(Return(kTestFailedErrno)); | 317 .WillOnce(Return(kTestFailedErrno)); |
| 226 EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno)) | 318 EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno)) |
| 227 .WillOnce(Return(kDummyMessage)); | 319 .WillOnce(Return(kDummyMessage)); |
| 228 | 320 |
| 229 // If open fails, the stream stays in kCreated because it has effectively had | 321 // Open still succeeds since PcmOpen is delegated to another thread. |
| 230 // no changes. | 322 ASSERT_TRUE(test_stream_->Open(kTestPacketSize)); |
| 231 ASSERT_FALSE(test_stream_->Open(kTestPacketSize)); | 323 ASSERT_EQ(AlsaPcmOutputStream::kIsOpened, |
| 232 EXPECT_EQ(AlsaPcmOutputStream::kCreated, | |
| 233 test_stream_->shared_data_.state()); | 324 test_stream_->shared_data_.state()); |
| 325 ASSERT_FALSE(test_stream_->stop_stream_); |
| 326 message_loop_.RunAllPending(); |
| 327 |
| 328 // Ensure internal state is set for a no-op stream if PcmOpen() failes. |
| 329 EXPECT_EQ(AlsaPcmOutputStream::kIsOpened, |
| 330 test_stream_->shared_data_.state()); |
| 331 EXPECT_TRUE(test_stream_->stop_stream_); |
| 332 EXPECT_TRUE(test_stream_->playback_handle_ == NULL); |
| 333 EXPECT_FALSE(test_stream_->packet_.get()); |
| 334 |
| 335 // Close the stream since we opened it to make destruction happy. |
| 336 EXPECT_CALL(mock_manager_, ReleaseStream(test_stream_.get())); |
| 337 test_stream_->Close(); |
| 338 message_loop_.RunAllPending(); |
| 234 } | 339 } |
| 235 | 340 |
| 236 TEST_F(AlsaPcmOutputStreamTest, PcmSetParamsFailed) { | 341 TEST_F(AlsaPcmOutputStreamTest, PcmSetParamsFailed) { |
| 237 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _)) | 342 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _)) |
| 238 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), | 343 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), |
| 239 Return(0))); | 344 Return(0))); |
| 240 EXPECT_CALL(mock_alsa_wrapper_, PcmSetParams(_, _, _, _, _, _, _)) | 345 EXPECT_CALL(mock_alsa_wrapper_, PcmSetParams(_, _, _, _, _, _, _)) |
| 241 .WillOnce(Return(kTestFailedErrno)); | 346 .WillOnce(Return(kTestFailedErrno)); |
| 242 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle)) | 347 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle)) |
| 243 .WillOnce(Return(0)); | 348 .WillOnce(Return(0)); |
| 244 EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno)) | 349 EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno)) |
| 245 .WillOnce(Return(kDummyMessage)); | 350 .WillOnce(Return(kDummyMessage)); |
| 246 | 351 |
| 247 // If open fails, the stream stays in kCreated because it has effectively had | 352 // If open fails, the stream stays in kCreated because it has effectively had |
| 248 // no changes. | 353 // no changes. |
| 249 ASSERT_FALSE(test_stream_->Open(kTestPacketSize)); | 354 ASSERT_TRUE(test_stream_->Open(kTestPacketSize)); |
| 250 EXPECT_EQ(AlsaPcmOutputStream::kCreated, | 355 EXPECT_EQ(AlsaPcmOutputStream::kIsOpened, |
| 251 test_stream_->shared_data_.state()); | 356 test_stream_->shared_data_.state()); |
| 357 ASSERT_FALSE(test_stream_->stop_stream_); |
| 358 message_loop_.RunAllPending(); |
| 359 |
| 360 // Ensure internal state is set for a no-op stream if PcmSetParams() failes. |
| 361 EXPECT_EQ(AlsaPcmOutputStream::kIsOpened, |
| 362 test_stream_->shared_data_.state()); |
| 363 EXPECT_TRUE(test_stream_->stop_stream_); |
| 364 EXPECT_TRUE(test_stream_->playback_handle_ == NULL); |
| 365 EXPECT_FALSE(test_stream_->packet_.get()); |
| 366 |
| 367 // Close the stream since we opened it to make destruction happy. |
| 368 EXPECT_CALL(mock_manager_, ReleaseStream(test_stream_.get())); |
| 369 test_stream_->Close(); |
| 370 message_loop_.RunAllPending(); |
| 252 } | 371 } |
| 253 | 372 |
| 254 TEST_F(AlsaPcmOutputStreamTest, StartStop) { | 373 TEST_F(AlsaPcmOutputStreamTest, StartStop) { |
| 255 // Open() call opens the playback device, sets the parameters, posts a task | 374 // Open() call opens the playback device, sets the parameters, posts a task |
| 256 // with the resulting configuration data, and transitions the object state to | 375 // with the resulting configuration data, and transitions the object state to |
| 257 // kIsOpened. | 376 // kIsOpened. |
| 258 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _)) | 377 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _)) |
| 259 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), | 378 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), |
| 260 Return(0))); | 379 Return(0))); |
| 261 EXPECT_CALL(mock_alsa_wrapper_, PcmSetParams(_, _, _, _, _, _, _)) | 380 EXPECT_CALL(mock_alsa_wrapper_, PcmSetParams(_, _, _, _, _, _, _)) |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 379 EXPECT_EQ(10u, packet_.size); | 498 EXPECT_EQ(10u, packet_.size); |
| 380 } | 499 } |
| 381 | 500 |
| 382 TEST_F(AlsaPcmOutputStreamTest, BufferPacket_UnfinishedPacket) { | 501 TEST_F(AlsaPcmOutputStreamTest, BufferPacket_UnfinishedPacket) { |
| 383 // No expectations set on the strict mock because nothing should be called. | 502 // No expectations set on the strict mock because nothing should be called. |
| 384 test_stream_->BufferPacket(&packet_); | 503 test_stream_->BufferPacket(&packet_); |
| 385 EXPECT_EQ(0u, packet_.used); | 504 EXPECT_EQ(0u, packet_.used); |
| 386 EXPECT_EQ(kTestPacketSize, packet_.size); | 505 EXPECT_EQ(kTestPacketSize, packet_.size); |
| 387 } | 506 } |
| 388 | 507 |
| 508 TEST_F(AlsaPcmOutputStreamTest, AutoSelectDevice_DeviceSelect) { |
| 509 // Try channels from 1 -> 9. and see that we get the more specific surroundXX |
| 510 // device opened for channels 4-8. For all other channels, the device should |
| 511 // default to |AlsaPcmOutputStream::kDefaultDevice|. We should also not |
| 512 // downmix any channel in this case because downmixing is only defined for |
| 513 // channels 4-8, which we are guaranteeing to work. |
| 514 // |
| 515 // Note that the loop starts at "1", so the first parameter is ignored in |
| 516 // these arrays. |
| 517 const char* kExpectedDeviceName[] = { NULL, |
| 518 AlsaPcmOutputStream::kDefaultDevice, |
| 519 AlsaPcmOutputStream::kDefaultDevice, |
| 520 AlsaPcmOutputStream::kDefaultDevice, |
| 521 kSurround40, kSurround50, kSurround51, |
| 522 kSurround70, kSurround71, |
| 523 AlsaPcmOutputStream::kDefaultDevice }; |
| 524 bool kExpectedDownmix[] = { false, false, false, false, false, false, |
| 525 false, false, false, false }; |
| 526 |
| 527 for (int i = 1; i <= 9; ++i) { |
| 528 SCOPED_TRACE(StringPrintf("Attempting %d Channel", i)); |
| 529 |
| 530 // Hints will only be grabbed for channel numbers that have non-default |
| 531 // devices associated with them. |
| 532 if (kExpectedDeviceName[i] != AlsaPcmOutputStream::kDefaultDevice) { |
| 533 // The DeviceNameHint and DeviceNameFreeHint need to be paired to avoid a |
| 534 // memory leak. |
| 535 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameHint(_, _, _)) |
| 536 .WillOnce(DoAll(SetArgumentPointee<2>(&kFakeHints[0]), Return(0))); |
| 537 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameFreeHint(&kFakeHints[0])) |
| 538 .Times(1); |
| 539 } |
| 540 |
| 541 EXPECT_CALL(mock_alsa_wrapper_, |
| 542 PcmOpen(_, StrEq(kExpectedDeviceName[i]), _, _)) |
| 543 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), Return(0))); |
| 544 EXPECT_CALL(mock_alsa_wrapper_, |
| 545 PcmSetParams(kFakeHandle, _, _, i, _, _, _)) |
| 546 .WillOnce(Return(0)); |
| 547 |
| 548 // The parameters are specified by ALSA documentation, and are in constants |
| 549 // in the implementation files. |
| 550 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameGetHint(_, StrEq("IOID"))) |
| 551 .WillRepeatedly(Invoke(OutputHint)); |
| 552 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameGetHint(_, StrEq("NAME"))) |
| 553 .WillRepeatedly(Invoke(EchoHint)); |
| 554 |
| 555 |
| 556 test_stream_ = CreateStreamWithChannels(i); |
| 557 EXPECT_TRUE(test_stream_->AutoSelectDevice(i)); |
| 558 EXPECT_EQ(kExpectedDownmix[i], test_stream_->should_downmix_); |
| 559 |
| 560 Mock::VerifyAndClearExpectations(&mock_alsa_wrapper_); |
| 561 Mock::VerifyAndClearExpectations(&mock_manager_); |
| 562 } |
| 563 } |
| 564 |
| 565 TEST_F(AlsaPcmOutputStreamTest, AutoSelectDevice_FallbackDevices) { |
| 566 using std::string; |
| 567 |
| 568 // If there are problems opening a multi-channel device, it the fallbacks |
| 569 // operations should be as follows. Assume the multi-channel device name is |
| 570 // surround50: |
| 571 // |
| 572 // 1) Try open "surround50" |
| 573 // 2) Try open "plug:surround50". |
| 574 // 3) Try open "default". |
| 575 // 4) Try open "plug:default". |
| 576 // 5) Give up trying to open. |
| 577 // |
| 578 const string first_try = kSurround50; |
| 579 const string second_try = string(AlsaPcmOutputStream::kPlugPrefix) + |
| 580 kSurround50; |
| 581 const string third_try = AlsaPcmOutputStream::kDefaultDevice; |
| 582 const string fourth_try = string(AlsaPcmOutputStream::kPlugPrefix) + |
| 583 AlsaPcmOutputStream::kDefaultDevice; |
| 584 |
| 585 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameHint(_, _, _)) |
| 586 .WillOnce(DoAll(SetArgumentPointee<2>(&kFakeHints[0]), Return(0))); |
| 587 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameFreeHint(&kFakeHints[0])) |
| 588 .Times(1); |
| 589 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameGetHint(_, StrEq("IOID"))) |
| 590 .WillRepeatedly(Invoke(OutputHint)); |
| 591 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameGetHint(_, StrEq("NAME"))) |
| 592 .WillRepeatedly(Invoke(EchoHint)); |
| 593 EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno)) |
| 594 .WillRepeatedly(Return(kDummyMessage)); |
| 595 |
| 596 InSequence s; |
| 597 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, StrEq(first_try.c_str()), _, _)) |
| 598 .WillOnce(Return(kTestFailedErrno)); |
| 599 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, StrEq(second_try.c_str()), _, _)) |
| 600 .WillOnce(Return(kTestFailedErrno)); |
| 601 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, StrEq(third_try.c_str()), _, _)) |
| 602 .WillOnce(Return(kTestFailedErrno)); |
| 603 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, StrEq(fourth_try.c_str()), _, _)) |
| 604 .WillOnce(Return(kTestFailedErrno)); |
| 605 |
| 606 test_stream_ = CreateStreamWithChannels(5); |
| 607 EXPECT_FALSE(test_stream_->AutoSelectDevice(5)); |
| 608 } |
| 609 |
| 610 TEST_F(AlsaPcmOutputStreamTest, AutoSelectDevice_HintFail) { |
| 611 // Should get |kDefaultDevice|, and force a 2-channel downmix on a failure to |
| 612 // enumerate devices. |
| 613 EXPECT_CALL(mock_alsa_wrapper_, DeviceNameHint(_, _, _)) |
| 614 .WillRepeatedly(Return(kTestFailedErrno)); |
| 615 EXPECT_CALL(mock_alsa_wrapper_, |
| 616 PcmOpen(_, StrEq(AlsaPcmOutputStream::kDefaultDevice), _, _)) |
| 617 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle), Return(0))); |
| 618 EXPECT_CALL(mock_alsa_wrapper_, |
| 619 PcmSetParams(kFakeHandle, _, _, 2, _, _, _)) |
| 620 .WillOnce(Return(0)); |
| 621 EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno)) |
| 622 .WillOnce(Return(kDummyMessage)); |
| 623 |
| 624 test_stream_ = CreateStreamWithChannels(5); |
| 625 EXPECT_TRUE(test_stream_->AutoSelectDevice(5)); |
| 626 EXPECT_TRUE(test_stream_->should_downmix_); |
| 627 } |
| 628 |
| 389 TEST_F(AlsaPcmOutputStreamTest, BufferPacket_StopStream) { | 629 TEST_F(AlsaPcmOutputStreamTest, BufferPacket_StopStream) { |
| 390 test_stream_->stop_stream_ = true; | 630 test_stream_->stop_stream_ = true; |
| 391 test_stream_->BufferPacket(&packet_); | 631 test_stream_->BufferPacket(&packet_); |
| 392 EXPECT_EQ(0u, packet_.used); | 632 EXPECT_EQ(0u, packet_.used); |
| 393 EXPECT_EQ(0u, packet_.size); | 633 EXPECT_EQ(0u, packet_.size); |
| 394 } | 634 } |
| 395 | 635 |
| 396 TEST_F(AlsaPcmOutputStreamTest, ScheduleNextWrite) { | 636 TEST_F(AlsaPcmOutputStreamTest, ScheduleNextWrite) { |
| 397 test_stream_->shared_data_.TransitionTo(AlsaPcmOutputStream::kIsOpened); | 637 test_stream_->shared_data_.TransitionTo(AlsaPcmOutputStream::kIsOpened); |
| 398 test_stream_->shared_data_.TransitionTo(AlsaPcmOutputStream::kIsPlaying); | 638 test_stream_->shared_data_.TransitionTo(AlsaPcmOutputStream::kIsPlaying); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 410 | 650 |
| 411 test_stream_->stop_stream_ = true; | 651 test_stream_->stop_stream_ = true; |
| 412 test_stream_->ScheduleNextWrite(&packet_); | 652 test_stream_->ScheduleNextWrite(&packet_); |
| 413 | 653 |
| 414 // TODO(ajwong): Find a way to test whether or not another task has been | 654 // TODO(ajwong): Find a way to test whether or not another task has been |
| 415 // posted so we can verify that the Alsa code will indeed break the task | 655 // posted so we can verify that the Alsa code will indeed break the task |
| 416 // posting loop. | 656 // posting loop. |
| 417 | 657 |
| 418 test_stream_->shared_data_.TransitionTo(AlsaPcmOutputStream::kIsClosed); | 658 test_stream_->shared_data_.TransitionTo(AlsaPcmOutputStream::kIsClosed); |
| 419 } | 659 } |
| OLD | NEW |