Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(541)

Side by Side Diff: media/audio/linux/alsa_output_unittest.cc

Issue 160497: Reimplement the AlsaPcmOutputStream and fix the threading issues. (Closed)
Patch Set: Address Andrew's comments. Diff aginst Patch 8 please. Created 11 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/audio/linux/alsa_output.cc ('k') | media/audio/linux/alsa_wrapper.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "base/logging.h"
6 #include "media/audio/linux/alsa_output.h"
7 #include "media/audio/linux/alsa_wrapper.h"
8 #include "testing/gmock/include/gmock/gmock.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10
11 using testing::_;
12 using testing::DoAll;
13 using testing::Eq;
14 using testing::Return;
15 using testing::SetArgumentPointee;
16 using testing::StrictMock;
17 using testing::StrEq;
18
19 class MockAlsaWrapper : public AlsaWrapper {
20 public:
21 MOCK_METHOD4(PcmOpen, int(snd_pcm_t** handle, const char* name,
22 snd_pcm_stream_t stream, int mode));
23 MOCK_METHOD1(PcmClose, int(snd_pcm_t* handle));
24 MOCK_METHOD1(PcmPrepare, int(snd_pcm_t* handle));
25 MOCK_METHOD1(PcmDrop, int(snd_pcm_t* handle));
26 MOCK_METHOD3(PcmWritei, snd_pcm_sframes_t(snd_pcm_t* handle,
27 const void* buffer,
28 snd_pcm_uframes_t size));
29 MOCK_METHOD3(PcmRecover, int(snd_pcm_t* handle, int err, int silent));
30 MOCK_METHOD7(PcmSetParams, int(snd_pcm_t* handle, snd_pcm_format_t format,
31 snd_pcm_access_t access, unsigned int channels,
32 unsigned int rate, int soft_resample,
33 unsigned int latency));
34 MOCK_METHOD1(PcmName, const char*(snd_pcm_t* handle));
35 MOCK_METHOD1(PcmAvailUpdate, snd_pcm_sframes_t (snd_pcm_t* handle));
36
37 MOCK_METHOD1(StrError, const char*(int errnum));
38 };
39
40 class MockAudioSourceCallback : public AudioOutputStream::AudioSourceCallback {
41 public:
42 MOCK_METHOD3(OnMoreData, size_t(AudioOutputStream* stream,
43 void* dest, size_t max_size));
44 MOCK_METHOD1(OnClose, void(AudioOutputStream* stream));
45 MOCK_METHOD2(OnError, void(AudioOutputStream* stream, int code));
46 };
47
48 class AlsaPcmOutputStreamTest : public testing::Test {
49 protected:
50 AlsaPcmOutputStreamTest()
51 : packet_(kTestPacketSize + 1) {
52 test_stream_ = new AlsaPcmOutputStream(kTestDeviceName,
53 kTestFormat,
54 kTestChannels,
55 kTestSampleRate,
56 kTestBitsPerSample,
57 &mock_alsa_wrapper_,
58 &message_loop_);
59
60 packet_.size = kTestPacketSize;
61 }
62
63 virtual ~AlsaPcmOutputStreamTest() {
64 test_stream_ = NULL;
65 }
66
67 static const int kTestChannels;
68 static const int kTestSampleRate;
69 static const int kTestBitsPerSample;
70 static const int kTestBytesPerFrame;
71 static const AudioManager::Format kTestFormat;
72 static const char kTestDeviceName[];
73 static const char kDummyMessage[];
74 static const int kTestFramesPerPacket;
75 static const size_t kTestPacketSize;
76 static const int kTestFailedErrno;
77 static snd_pcm_t* const kFakeHandle;
78
79 StrictMock<MockAlsaWrapper> mock_alsa_wrapper_;
80 MessageLoop message_loop_;
81 scoped_refptr<AlsaPcmOutputStream> test_stream_;
82 AlsaPcmOutputStream::Packet packet_;
83
84 private:
85 DISALLOW_COPY_AND_ASSIGN(AlsaPcmOutputStreamTest);
86 };
87
88 const int AlsaPcmOutputStreamTest::kTestChannels = 2;
89 const int AlsaPcmOutputStreamTest::kTestSampleRate =
90 AudioManager::kAudioCDSampleRate;
91 const int AlsaPcmOutputStreamTest::kTestBitsPerSample = 8;
92 const int AlsaPcmOutputStreamTest::kTestBytesPerFrame =
93 AlsaPcmOutputStreamTest::kTestBitsPerSample / 8 *
94 AlsaPcmOutputStreamTest::kTestChannels;
95 const AudioManager::Format AlsaPcmOutputStreamTest::kTestFormat =
96 AudioManager::AUDIO_PCM_LINEAR;
97 const char AlsaPcmOutputStreamTest::kTestDeviceName[] = "TestDevice";
98 const char AlsaPcmOutputStreamTest::kDummyMessage[] = "dummy";
99 const int AlsaPcmOutputStreamTest::kTestFramesPerPacket = 100;
100 const size_t AlsaPcmOutputStreamTest::kTestPacketSize =
101 AlsaPcmOutputStreamTest::kTestFramesPerPacket *
102 AlsaPcmOutputStreamTest::kTestBytesPerFrame;
103 const int AlsaPcmOutputStreamTest::kTestFailedErrno = -EACCES;
104 snd_pcm_t* const AlsaPcmOutputStreamTest::kFakeHandle =
105 reinterpret_cast<snd_pcm_t*>(1);
106
107 TEST_F(AlsaPcmOutputStreamTest, ConstructedState) {
108 EXPECT_EQ(AlsaPcmOutputStream::kCreated,
109 test_stream_->shared_data_.state());
110
111 // Only supports 2 channel.
112 test_stream_ = new AlsaPcmOutputStream(kTestDeviceName,
113 kTestFormat,
114 kTestChannels + 1,
115 kTestSampleRate,
116 kTestBitsPerSample,
117 &mock_alsa_wrapper_,
118 &message_loop_);
119 EXPECT_EQ(AlsaPcmOutputStream::kInError,
120 test_stream_->shared_data_.state());
121
122 // Bad bits per sample.
123 test_stream_ = new AlsaPcmOutputStream(kTestDeviceName,
124 kTestFormat,
125 kTestChannels,
126 kTestSampleRate,
127 kTestBitsPerSample - 1,
128 &mock_alsa_wrapper_,
129 &message_loop_);
130 EXPECT_EQ(AlsaPcmOutputStream::kInError,
131 test_stream_->shared_data_.state());
132
133 // Bad format.
134 test_stream_ = new AlsaPcmOutputStream(kTestDeviceName,
135 AudioManager::AUDIO_PCM_DELTA,
136 kTestChannels,
137 kTestSampleRate,
138 kTestBitsPerSample,
139 &mock_alsa_wrapper_,
140 &message_loop_);
141 EXPECT_EQ(AlsaPcmOutputStream::kInError,
142 test_stream_->shared_data_.state());
143 }
144
145 TEST_F(AlsaPcmOutputStreamTest, OpenClose) {
146 int64 expected_micros = 2 *
147 AlsaPcmOutputStream::FramesToMicros(kTestPacketSize / kTestBytesPerFrame,
148 kTestSampleRate);
149
150 // Open() call opens the playback device, sets the parameters, posts a task
151 // with the resulting configuration data, and transitions the object state to
152 // kIsOpened.
153 EXPECT_CALL(mock_alsa_wrapper_,
154 PcmOpen(_, StrEq(kTestDeviceName),
155 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK))
156 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle),
157 Return(0)));
158 EXPECT_CALL(mock_alsa_wrapper_,
159 PcmSetParams(kFakeHandle,
160 SND_PCM_FORMAT_S8,
161 SND_PCM_ACCESS_RW_INTERLEAVED,
162 kTestChannels,
163 kTestSampleRate,
164 1,
165 expected_micros))
166 .WillOnce(Return(0));
167
168 // Open the stream.
169 ASSERT_TRUE(test_stream_->Open(kTestPacketSize));
170 message_loop_.RunAllPending();
171
172 EXPECT_EQ(AlsaPcmOutputStream::kIsOpened,
173 test_stream_->shared_data_.state());
174 EXPECT_EQ(kFakeHandle, test_stream_->playback_handle_);
175 EXPECT_EQ(kTestFramesPerPacket, test_stream_->frames_per_packet_);
176 EXPECT_TRUE(test_stream_->packet_.get());
177 EXPECT_FALSE(test_stream_->stop_stream_);
178
179 // Now close it and test that everything was released.
180 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle))
181 .WillOnce(Return(0));
182 test_stream_->Close();
183 message_loop_.RunAllPending();
184
185 EXPECT_EQ(NULL, test_stream_->playback_handle_);
186 EXPECT_FALSE(test_stream_->packet_.get());
187 EXPECT_TRUE(test_stream_->stop_stream_);
188 }
189
190 TEST_F(AlsaPcmOutputStreamTest, PcmOpenFailed) {
191 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _))
192 .WillOnce(Return(kTestFailedErrno));
193 EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno))
194 .WillOnce(Return(kDummyMessage));
195
196 // If open fails, the stream stays in kCreated because it has effectively had
197 // no changes.
198 ASSERT_FALSE(test_stream_->Open(kTestPacketSize));
199 EXPECT_EQ(AlsaPcmOutputStream::kCreated,
200 test_stream_->shared_data_.state());
201 }
202
203 TEST_F(AlsaPcmOutputStreamTest, PcmSetParamsFailed) {
204 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _))
205 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle),
206 Return(0)));
207 EXPECT_CALL(mock_alsa_wrapper_, PcmSetParams(_, _, _, _, _, _, _))
208 .WillOnce(Return(kTestFailedErrno));
209 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle))
210 .WillOnce(Return(0));
211 EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno))
212 .WillOnce(Return(kDummyMessage));
213
214 // If open fails, the stream stays in kCreated because it has effectively had
215 // no changes.
216 ASSERT_FALSE(test_stream_->Open(kTestPacketSize));
217 EXPECT_EQ(AlsaPcmOutputStream::kCreated,
218 test_stream_->shared_data_.state());
219 }
220
221 TEST_F(AlsaPcmOutputStreamTest, StartStop) {
222 // Open() call opens the playback device, sets the parameters, posts a task
223 // with the resulting configuration data, and transitions the object state to
224 // kIsOpened.
225 EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, _, _, _))
226 .WillOnce(DoAll(SetArgumentPointee<0>(kFakeHandle),
227 Return(0)));
228 EXPECT_CALL(mock_alsa_wrapper_, PcmSetParams(_, _, _, _, _, _, _))
229 .WillOnce(Return(0));
230
231 // Open the stream.
232 ASSERT_TRUE(test_stream_->Open(kTestPacketSize));
233 message_loop_.RunAllPending();
234
235 // Expect Device setup.
236 EXPECT_CALL(mock_alsa_wrapper_, PcmDrop(kFakeHandle))
237 .WillOnce(Return(0));
238 EXPECT_CALL(mock_alsa_wrapper_, PcmPrepare(kFakeHandle))
239 .WillOnce(Return(0));
240
241 // Expect the pre-roll.
242 MockAudioSourceCallback mock_callback;
243 EXPECT_CALL(mock_callback,
244 OnMoreData(test_stream_.get(), _, kTestPacketSize))
245 .Times(2)
246 .WillRepeatedly(Return(kTestPacketSize));
247 EXPECT_CALL(mock_alsa_wrapper_, PcmWritei(kFakeHandle, _, _))
248 .Times(2)
249 .WillRepeatedly(Return(kTestPacketSize));
250
251 // Expect scheduling.
252 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(kFakeHandle))
253 .WillOnce(Return(1));
254
255 test_stream_->Start(&mock_callback);
256 message_loop_.RunAllPending();
257
258 EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle))
259 .WillOnce(Return(0));
260 test_stream_->Close();
261 message_loop_.RunAllPending();
262 }
263
264 TEST_F(AlsaPcmOutputStreamTest, WritePacket_FinishedPacket) {
265 // Nothing should happen. Don't set any expectations and Our strict mocks
266 // should verify most of this.
267
268 // Test regular used-up packet.
269 packet_.used = packet_.size;
270 test_stream_->WritePacket(&packet_);
271
272 // Test empty packet.
273 packet_.used = packet_.size = 0;
274 test_stream_->WritePacket(&packet_);
275 }
276
277 TEST_F(AlsaPcmOutputStreamTest, WritePacket_NormalPacket) {
278 // Write a little less than half the data.
279 EXPECT_CALL(mock_alsa_wrapper_, PcmWritei(_, packet_.buffer.get(), _))
280 .WillOnce(Return(packet_.size / kTestBytesPerFrame / 2 - 1));
281
282 test_stream_->WritePacket(&packet_);
283
284 ASSERT_EQ(packet_.size / 2 - kTestBytesPerFrame, packet_.used);
285
286 // Write the rest.
287 EXPECT_CALL(mock_alsa_wrapper_,
288 PcmWritei(_, packet_.buffer.get() + packet_.used, _))
289 .WillOnce(Return(packet_.size / kTestBytesPerFrame / 2 + 1));
290 test_stream_->WritePacket(&packet_);
291 EXPECT_EQ(packet_.size, packet_.used);
292 }
293
294 TEST_F(AlsaPcmOutputStreamTest, WritePacket_WriteFails) {
295 // Fail due to a recoverable error and see that PcmRecover code path
296 // continues normally.
297 EXPECT_CALL(mock_alsa_wrapper_, PcmWritei(_, _, _))
298 .WillOnce(Return(-EINTR));
299 EXPECT_CALL(mock_alsa_wrapper_, PcmRecover(_, _, _))
300 .WillOnce(Return(packet_.size / kTestBytesPerFrame / 2 - 1));
301
302 test_stream_->WritePacket(&packet_);
303
304 ASSERT_EQ(packet_.size / 2 - kTestBytesPerFrame, packet_.used);
305
306 // Fail the next write, and see that stop_stream_ is set.
307 EXPECT_CALL(mock_alsa_wrapper_, PcmWritei(_, _, _))
308 .WillOnce(Return(kTestFailedErrno));
309 EXPECT_CALL(mock_alsa_wrapper_, PcmRecover(_, _, _))
310 .WillOnce(Return(kTestFailedErrno));
311 EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno))
312 .WillOnce(Return(kDummyMessage));
313 test_stream_->WritePacket(&packet_);
314 EXPECT_EQ(packet_.size / 2 - kTestBytesPerFrame, packet_.used);
315 EXPECT_TRUE(test_stream_->stop_stream_);
316 }
317
318 TEST_F(AlsaPcmOutputStreamTest, WritePacket_StopStream) {
319 // No expectations set on the strict mock because nothing should be called.
320 test_stream_->stop_stream_ = true;
321 test_stream_->WritePacket(&packet_);
322 EXPECT_EQ(packet_.size, packet_.used);
323 }
324
325 TEST_F(AlsaPcmOutputStreamTest, BufferPacket) {
326 packet_.used = packet_.size;
327
328 // Return a partially filled packet.
329 MockAudioSourceCallback mock_callback;
330 EXPECT_CALL(mock_callback,
331 OnMoreData(test_stream_.get(), packet_.buffer.get(),
332 packet_.capacity))
333 .WillOnce(Return(10));
334
335 test_stream_->source_callback_ = &mock_callback;
336 test_stream_->BufferPacket(&packet_);
337
338 EXPECT_EQ(0u, packet_.used);
339 EXPECT_EQ(10u, packet_.size);
340 }
341
342 TEST_F(AlsaPcmOutputStreamTest, BufferPacket_UnfinishedPacket) {
343 // No expectations set on the strict mock because nothing should be called.
344 test_stream_->BufferPacket(&packet_);
345 EXPECT_EQ(0u, packet_.used);
346 EXPECT_EQ(kTestPacketSize, packet_.size);
347 }
348
349 TEST_F(AlsaPcmOutputStreamTest, BufferPacket_StopStream) {
350 test_stream_->stop_stream_ = true;
351 test_stream_->BufferPacket(&packet_);
352 EXPECT_EQ(0u, packet_.used);
353 EXPECT_EQ(0u, packet_.size);
354 }
355
356 TEST_F(AlsaPcmOutputStreamTest, ScheduleNextWrite) {
357 test_stream_->shared_data_.TransitionTo(AlsaPcmOutputStream::kIsOpened);
358 test_stream_->shared_data_.TransitionTo(AlsaPcmOutputStream::kIsPlaying);
359
360 EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(_))
361 .WillOnce(Return(10));
362 test_stream_->ScheduleNextWrite(&packet_);
363
364 test_stream_->shared_data_.TransitionTo(AlsaPcmOutputStream::kIsClosed);
365 }
366
367 TEST_F(AlsaPcmOutputStreamTest, ScheduleNextWrite_StopStream) {
368 test_stream_->shared_data_.TransitionTo(AlsaPcmOutputStream::kIsOpened);
369 test_stream_->shared_data_.TransitionTo(AlsaPcmOutputStream::kIsPlaying);
370
371 test_stream_->stop_stream_ = true;
372 test_stream_->ScheduleNextWrite(&packet_);
373
374 // TODO(ajwong): Find a way to test whether or not another task has been
375 // posted so we can verify that the Alsa code will indeed break the task
376 // posting loop.
377
378 test_stream_->shared_data_.TransitionTo(AlsaPcmOutputStream::kIsClosed);
379 }
OLDNEW
« no previous file with comments | « media/audio/linux/alsa_output.cc ('k') | media/audio/linux/alsa_wrapper.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698