audio_output_controller_unittest.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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/basictypes.h"
6#include "base/bind.h"
7#include "base/environment.h"
8#include "base/logging.h"
9#include "base/memory/ref_counted.h"
10#include "base/memory/scoped_ptr.h"
11#include "base/message_loop.h"
12#include "base/synchronization/waitable_event.h"
13#include "media/audio/audio_output_controller.h"
14#include "media/audio/audio_parameters.h"
15#include "media/base/audio_bus.h"
16#include "testing/gmock/include/gmock/gmock.h"
17#include "testing/gtest/include/gtest/gtest.h"
18
19using ::testing::_;
20using ::testing::AtLeast;
21using ::testing::DoAll;
22using ::testing::Invoke;
23using ::testing::NotNull;
24using ::testing::Return;
25
26namespace media {
27
28static const int kSampleRate = AudioParameters::kAudioCDSampleRate;
29static const int kBitsPerSample = 16;
30static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO;
31static const int kSamplesPerPacket = kSampleRate / 100;
32static const int kHardwareBufferSize = kSamplesPerPacket *
33    ChannelLayoutToChannelCount(kChannelLayout) * kBitsPerSample / 8;
34static const double kTestVolume = 0.25;
35
36class MockAudioOutputControllerEventHandler
37    : public AudioOutputController::EventHandler {
38 public:
39  MockAudioOutputControllerEventHandler() {}
40
41  MOCK_METHOD0(OnCreated, void());
42  MOCK_METHOD0(OnPlaying, void());
43  MOCK_METHOD1(OnAudible, void(bool is_audible));
44  MOCK_METHOD0(OnPaused, void());
45  MOCK_METHOD0(OnError, void());
46  MOCK_METHOD2(OnDeviceChange, void(int new_buffer_size, int new_sample_rate));
47
48 private:
49  DISALLOW_COPY_AND_ASSIGN(MockAudioOutputControllerEventHandler);
50};
51
52class MockAudioOutputControllerSyncReader
53    : public AudioOutputController::SyncReader {
54 public:
55  MockAudioOutputControllerSyncReader() {}
56
57  MOCK_METHOD1(UpdatePendingBytes, void(uint32 bytes));
58  MOCK_METHOD2(Read, int(AudioBus* source, AudioBus* dest));
59  MOCK_METHOD0(Close, void());
60  MOCK_METHOD0(DataReady, bool());
61
62 private:
63  DISALLOW_COPY_AND_ASSIGN(MockAudioOutputControllerSyncReader);
64};
65
66class MockAudioOutputStream : public AudioOutputStream {
67 public:
68  MOCK_METHOD0(Open, bool());
69  MOCK_METHOD1(Start, void(AudioSourceCallback* callback));
70  MOCK_METHOD0(Stop, void());
71  MOCK_METHOD1(SetVolume, void(double volume));
72  MOCK_METHOD1(GetVolume, void(double* volume));
73  MOCK_METHOD0(Close, void());
74
75  // Set/get the callback passed to Start().
76  AudioSourceCallback* callback() const { return callback_; }
77  void SetCallback(AudioSourceCallback* asc) { callback_ = asc; }
78
79 private:
80  AudioSourceCallback* callback_;
81};
82
83ACTION_P(SignalEvent, event) {
84  event->Signal();
85}
86
87static const float kBufferNonZeroData = 1.0f;
88ACTION(PopulateBuffer) {
89  arg1->Zero();
90  // Note: To confirm the buffer will be populated in these tests, it's
91  // sufficient that only the first float in channel 0 is set to the value.
92  arg1->channel(0)[0] = kBufferNonZeroData;
93}
94
95class AudioOutputControllerTest : public testing::Test {
96 public:
97  AudioOutputControllerTest()
98      : audio_manager_(AudioManager::Create()),
99        create_event_(false, false),
100        play_event_(false, false),
101        read_event_(false, false),
102        pause_event_(false, false) {
103  }
104
105  virtual ~AudioOutputControllerTest() {
106  }
107
108 protected:
109  void Create(int samples_per_packet) {
110    EXPECT_FALSE(create_event_.IsSignaled());
111    EXPECT_FALSE(play_event_.IsSignaled());
112    EXPECT_FALSE(read_event_.IsSignaled());
113    EXPECT_FALSE(pause_event_.IsSignaled());
114
115    params_ = AudioParameters(
116        AudioParameters::AUDIO_FAKE, kChannelLayout,
117        kSampleRate, kBitsPerSample, samples_per_packet);
118
119    if (params_.IsValid()) {
120      EXPECT_CALL(mock_event_handler_, OnCreated())
121          .WillOnce(SignalEvent(&create_event_));
122    }
123
124    controller_ = AudioOutputController::Create(
125        audio_manager_.get(), &mock_event_handler_, params_,
126        &mock_sync_reader_);
127    if (controller_)
128      controller_->SetVolume(kTestVolume);
129
130    EXPECT_EQ(params_.IsValid(), controller_ != NULL);
131  }
132
133  void Play() {
134    // Expect the event handler to receive one OnPlaying() call and one or more
135    // OnAudible() calls.
136    EXPECT_CALL(mock_event_handler_, OnPlaying())
137        .WillOnce(SignalEvent(&play_event_));
138    EXPECT_CALL(mock_event_handler_, OnAudible(_))
139        .Times(AtLeast(1));
140
141    // During playback, the mock pretends to provide audio data rendered and
142    // sent from the render process.
143    EXPECT_CALL(mock_sync_reader_, UpdatePendingBytes(_))
144        .Times(AtLeast(1));
145    EXPECT_CALL(mock_sync_reader_, Read(_, _))
146        .WillRepeatedly(DoAll(PopulateBuffer(),
147                              SignalEvent(&read_event_),
148                              Return(params_.frames_per_buffer())));
149    EXPECT_CALL(mock_sync_reader_, DataReady())
150        .WillRepeatedly(Return(true));
151
152    controller_->Play();
153  }
154
155  void Pause() {
156    // Expect the event handler to receive one OnPaused() call.
157    EXPECT_CALL(mock_event_handler_, OnPaused())
158        .WillOnce(SignalEvent(&pause_event_));
159
160    controller_->Pause();
161  }
162
163  void ChangeDevice() {
164    // Expect the event handler to receive one OnPaying() call and no OnPaused()
165    // call.
166    EXPECT_CALL(mock_event_handler_, OnPlaying())
167        .WillOnce(SignalEvent(&play_event_));
168    EXPECT_CALL(mock_event_handler_, OnPaused())
169        .Times(0);
170
171    // Simulate a device change event to AudioOutputController from the
172    // AudioManager.
173    audio_manager_->GetMessageLoop()->PostTask(
174        FROM_HERE,
175        base::Bind(&AudioOutputController::OnDeviceChange, controller_));
176  }
177
178  void Divert(bool was_playing, int num_times_to_be_started) {
179    if (was_playing) {
180      // Expect the handler to receive one OnPlaying() call as a result of the
181      // stream switching.
182      EXPECT_CALL(mock_event_handler_, OnPlaying())
183          .WillOnce(SignalEvent(&play_event_));
184    }
185
186    EXPECT_CALL(mock_stream_, Open())
187        .WillOnce(Return(true));
188    EXPECT_CALL(mock_stream_, SetVolume(kTestVolume));
189    if (num_times_to_be_started > 0) {
190      EXPECT_CALL(mock_stream_, Start(NotNull()))
191          .Times(num_times_to_be_started)
192          .WillRepeatedly(
193              Invoke(&mock_stream_, &MockAudioOutputStream::SetCallback));
194      EXPECT_CALL(mock_stream_, Stop())
195          .Times(num_times_to_be_started);
196    }
197
198    controller_->StartDiverting(&mock_stream_);
199  }
200
201  void ReadDivertedAudioData() {
202    scoped_ptr<AudioBus> dest = AudioBus::Create(params_);
203    ASSERT_TRUE(!!mock_stream_.callback());
204    const int frames_read =
205        mock_stream_.callback()->OnMoreData(dest.get(), AudioBuffersState());
206    EXPECT_LT(0, frames_read);
207    EXPECT_EQ(kBufferNonZeroData, dest->channel(0)[0]);
208  }
209
210  void Revert(bool was_playing) {
211    if (was_playing) {
212      // Expect the handler to receive one OnPlaying() call as a result of the
213      // stream switching back.
214      EXPECT_CALL(mock_event_handler_, OnPlaying())
215          .WillOnce(SignalEvent(&play_event_));
216    }
217
218    EXPECT_CALL(mock_stream_, Close());
219
220    controller_->StopDiverting();
221  }
222
223  void Close() {
224    EXPECT_CALL(mock_sync_reader_, Close());
225
226    controller_->Close(base::MessageLoop::QuitClosure());
227    base::MessageLoop::current()->Run();
228  }
229
230  // These help make test sequences more readable.
231  void DivertNeverPlaying() { Divert(false, 0); }
232  void DivertWillEventuallyBeTwicePlayed() { Divert(false, 2); }
233  void DivertWhilePlaying() { Divert(true, 1); }
234  void RevertWasNotPlaying() { Revert(false); }
235  void RevertWhilePlaying() { Revert(true); }
236
237  // These synchronize the main thread with key events taking place on other
238  // threads.
239  void WaitForCreate() { create_event_.Wait(); }
240  void WaitForPlay() { play_event_.Wait(); }
241  void WaitForReads() {
242    // Note: Arbitrarily chosen, but more iterations causes tests to take
243    // significantly more time.
244    static const int kNumIterations = 3;
245    for (int i = 0; i < kNumIterations; ++i) {
246      read_event_.Wait();
247    }
248  }
249  void WaitForPause() { pause_event_.Wait(); }
250
251 private:
252  base::MessageLoopForIO message_loop_;
253  scoped_ptr<AudioManager> audio_manager_;
254  MockAudioOutputControllerEventHandler mock_event_handler_;
255  MockAudioOutputControllerSyncReader mock_sync_reader_;
256  MockAudioOutputStream mock_stream_;
257  base::WaitableEvent create_event_;
258  base::WaitableEvent play_event_;
259  base::WaitableEvent read_event_;
260  base::WaitableEvent pause_event_;
261  AudioParameters params_;
262  scoped_refptr<AudioOutputController> controller_;
263
264  DISALLOW_COPY_AND_ASSIGN(AudioOutputControllerTest);
265};
266
267TEST_F(AudioOutputControllerTest, CreateAndClose) {
268  Create(kSamplesPerPacket);
269  Close();
270}
271
272TEST_F(AudioOutputControllerTest, HardwareBufferTooLarge) {
273  Create(kSamplesPerPacket * 1000);
274}
275
276TEST_F(AudioOutputControllerTest, PlayAndClose) {
277  Create(kSamplesPerPacket);
278  WaitForCreate();
279  Play();
280  WaitForPlay();
281  WaitForReads();
282  Close();
283}
284
285TEST_F(AudioOutputControllerTest, PlayPauseClose) {
286  Create(kSamplesPerPacket);
287  WaitForCreate();
288  Play();
289  WaitForPlay();
290  WaitForReads();
291  Pause();
292  WaitForPause();
293  Close();
294}
295
296TEST_F(AudioOutputControllerTest, PlayPausePlayClose) {
297  Create(kSamplesPerPacket);
298  WaitForCreate();
299  Play();
300  WaitForPlay();
301  WaitForReads();
302  Pause();
303  WaitForPause();
304  Play();
305  WaitForPlay();
306  Close();
307}
308
309TEST_F(AudioOutputControllerTest, PlayDeviceChangeClose) {
310  Create(kSamplesPerPacket);
311  WaitForCreate();
312  Play();
313  WaitForPlay();
314  WaitForReads();
315  ChangeDevice();
316  WaitForPlay();
317  WaitForReads();
318  Close();
319}
320
321TEST_F(AudioOutputControllerTest, PlayDivertRevertClose) {
322  Create(kSamplesPerPacket);
323  WaitForCreate();
324  Play();
325  WaitForPlay();
326  WaitForReads();
327  DivertWhilePlaying();
328  WaitForPlay();
329  ReadDivertedAudioData();
330  RevertWhilePlaying();
331  WaitForPlay();
332  WaitForReads();
333  Close();
334}
335
336TEST_F(AudioOutputControllerTest, PlayDivertRevertDivertRevertClose) {
337  Create(kSamplesPerPacket);
338  WaitForCreate();
339  Play();
340  WaitForPlay();
341  WaitForReads();
342  DivertWhilePlaying();
343  WaitForPlay();
344  ReadDivertedAudioData();
345  RevertWhilePlaying();
346  WaitForPlay();
347  WaitForReads();
348  DivertWhilePlaying();
349  WaitForPlay();
350  ReadDivertedAudioData();
351  RevertWhilePlaying();
352  WaitForPlay();
353  WaitForReads();
354  Close();
355}
356
357TEST_F(AudioOutputControllerTest, DivertPlayPausePlayRevertClose) {
358  Create(kSamplesPerPacket);
359  WaitForCreate();
360  DivertWillEventuallyBeTwicePlayed();
361  Play();
362  WaitForPlay();
363  ReadDivertedAudioData();
364  Pause();
365  WaitForPause();
366  Play();
367  WaitForPlay();
368  ReadDivertedAudioData();
369  RevertWhilePlaying();
370  WaitForPlay();
371  WaitForReads();
372  Close();
373}
374
375TEST_F(AudioOutputControllerTest, DivertRevertClose) {
376  Create(kSamplesPerPacket);
377  WaitForCreate();
378  DivertNeverPlaying();
379  RevertWasNotPlaying();
380  Close();
381}
382
383}  // namespace media
384