Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / media / audio / audio_output_device_unittest.cc
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 <vector>
6
7 #include "base/at_exit.h"
8 #include "base/memory/shared_memory.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/process/process_handle.h"
11 #include "base/sync_socket.h"
12 #include "base/test/test_timeouts.h"
13 #include "media/audio/audio_output_device.h"
14 #include "media/audio/sample_rates.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gmock_mutant.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18
19 using base::CancelableSyncSocket;
20 using base::SharedMemory;
21 using base::SyncSocket;
22 using testing::_;
23 using testing::DoAll;
24 using testing::Invoke;
25 using testing::Return;
26 using testing::WithArgs;
27 using testing::StrictMock;
28 using testing::Values;
29
30 namespace media {
31
32 namespace {
33
34 class MockRenderCallback : public AudioRendererSink::RenderCallback {
35  public:
36   MockRenderCallback() {}
37   virtual ~MockRenderCallback() {}
38
39   MOCK_METHOD2(Render, int(AudioBus* dest, int audio_delay_milliseconds));
40   MOCK_METHOD3(RenderIO, void(AudioBus* source,
41                               AudioBus* dest,
42                               int audio_delay_milliseconds));
43   MOCK_METHOD0(OnRenderError, void());
44 };
45
46 class MockAudioOutputIPC : public AudioOutputIPC {
47  public:
48   MockAudioOutputIPC() {}
49   virtual ~MockAudioOutputIPC() {}
50
51   MOCK_METHOD3(CreateStream, void(AudioOutputIPCDelegate* delegate,
52                                   const AudioParameters& params,
53                                   int session_id));
54   MOCK_METHOD0(PlayStream, void());
55   MOCK_METHOD0(PauseStream, void());
56   MOCK_METHOD0(CloseStream, void());
57   MOCK_METHOD1(SetVolume, void(double volume));
58 };
59
60 // Creates a copy of a SyncSocket handle that we can give to AudioOutputDevice.
61 // On Windows this means duplicating the pipe handle so that AudioOutputDevice
62 // can call CloseHandle() (since ownership has been transferred), but on other
63 // platforms, we just copy the same socket handle since AudioOutputDevice on
64 // those platforms won't actually own the socket (FileDescriptor.auto_close is
65 // false).
66 bool DuplicateSocketHandle(SyncSocket::Handle socket_handle,
67                            SyncSocket::Handle* copy) {
68 #if defined(OS_WIN)
69   HANDLE process = GetCurrentProcess();
70   ::DuplicateHandle(process, socket_handle, process, copy,
71                     0, FALSE, DUPLICATE_SAME_ACCESS);
72   return *copy != NULL;
73 #else
74   *copy = socket_handle;
75   return *copy != -1;
76 #endif
77 }
78
79 ACTION_P2(SendPendingBytes, socket, pending_bytes) {
80   socket->Send(&pending_bytes, sizeof(pending_bytes));
81 }
82
83 // Used to terminate a loop from a different thread than the loop belongs to.
84 // |loop| should be a MessageLoopProxy.
85 ACTION_P(QuitLoop, loop) {
86   loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
87 }
88
89 }  // namespace.
90
91 class AudioOutputDeviceTest
92     : public testing::Test,
93       public testing::WithParamInterface<bool> {
94  public:
95   AudioOutputDeviceTest();
96   ~AudioOutputDeviceTest();
97
98   void StartAudioDevice();
99   void CreateStream();
100   void ExpectRenderCallback();
101   void WaitUntilRenderCallback();
102   void StopAudioDevice();
103
104  protected:
105   // Used to clean up TLS pointers that the test(s) will initialize.
106   // Must remain the first member of this class.
107   base::ShadowingAtExitManager at_exit_manager_;
108   base::MessageLoopForIO io_loop_;
109   AudioParameters default_audio_parameters_;
110   StrictMock<MockRenderCallback> callback_;
111   MockAudioOutputIPC* audio_output_ipc_;  // owned by audio_device_
112   scoped_refptr<AudioOutputDevice> audio_device_;
113
114  private:
115   int CalculateMemorySize();
116
117   const bool synchronized_io_;
118   const int input_channels_;
119   SharedMemory shared_memory_;
120   CancelableSyncSocket browser_socket_;
121   CancelableSyncSocket renderer_socket_;
122
123   DISALLOW_COPY_AND_ASSIGN(AudioOutputDeviceTest);
124 };
125
126 int AudioOutputDeviceTest::CalculateMemorySize() {
127   // Calculate output and input memory size.
128   int output_memory_size =
129       AudioBus::CalculateMemorySize(default_audio_parameters_);
130
131   int frames = default_audio_parameters_.frames_per_buffer();
132   int input_memory_size =
133       AudioBus::CalculateMemorySize(input_channels_, frames);
134
135   return output_memory_size + input_memory_size;
136 }
137
138 AudioOutputDeviceTest::AudioOutputDeviceTest()
139     : synchronized_io_(GetParam()),
140       input_channels_(synchronized_io_ ? 2 : 0) {
141   default_audio_parameters_.Reset(
142       AudioParameters::AUDIO_PCM_LINEAR,
143       CHANNEL_LAYOUT_STEREO, 2, input_channels_,
144       48000, 16, 1024);
145
146   audio_output_ipc_ = new MockAudioOutputIPC();
147   audio_device_ = new AudioOutputDevice(
148       scoped_ptr<AudioOutputIPC>(audio_output_ipc_),
149       io_loop_.message_loop_proxy());
150
151   audio_device_->Initialize(default_audio_parameters_,
152                             &callback_);
153
154   io_loop_.RunUntilIdle();
155 }
156
157 AudioOutputDeviceTest::~AudioOutputDeviceTest() {
158   audio_device_ = NULL;
159 }
160
161 void AudioOutputDeviceTest::StartAudioDevice() {
162   audio_device_->Start();
163
164   EXPECT_CALL(*audio_output_ipc_, CreateStream(audio_device_.get(), _, 0));
165
166   io_loop_.RunUntilIdle();
167 }
168
169 void AudioOutputDeviceTest::CreateStream() {
170   const int kMemorySize = CalculateMemorySize();
171
172   ASSERT_TRUE(shared_memory_.CreateAndMapAnonymous(kMemorySize));
173   memset(shared_memory_.memory(), 0xff, kMemorySize);
174
175   ASSERT_TRUE(CancelableSyncSocket::CreatePair(&browser_socket_,
176                                                &renderer_socket_));
177
178   // Create duplicates of the handles we pass to AudioOutputDevice since
179   // ownership will be transferred and AudioOutputDevice is responsible for
180   // freeing.
181   SyncSocket::Handle audio_device_socket = SyncSocket::kInvalidHandle;
182   ASSERT_TRUE(DuplicateSocketHandle(renderer_socket_.handle(),
183                                     &audio_device_socket));
184   base::SharedMemoryHandle duplicated_memory_handle;
185   ASSERT_TRUE(shared_memory_.ShareToProcess(base::GetCurrentProcessHandle(),
186                                             &duplicated_memory_handle));
187
188   audio_device_->OnStreamCreated(duplicated_memory_handle, audio_device_socket,
189                                  kMemorySize);
190   io_loop_.RunUntilIdle();
191 }
192
193 void AudioOutputDeviceTest::ExpectRenderCallback() {
194   // We should get a 'play' notification when we call OnStreamCreated().
195   // Respond by asking for some audio data.  This should ask our callback
196   // to provide some audio data that AudioOutputDevice then writes into the
197   // shared memory section.
198   const int kMemorySize = CalculateMemorySize();
199
200   EXPECT_CALL(*audio_output_ipc_, PlayStream())
201       .WillOnce(SendPendingBytes(&browser_socket_, kMemorySize));
202
203   // We expect calls to our audio renderer callback, which returns the number
204   // of frames written to the memory section.
205   // Here's the second place where it gets hacky:  There's no way for us to
206   // know (without using a sleep loop!) when the AudioOutputDevice has finished
207   // writing the interleaved audio data into the shared memory section.
208   // So, for the sake of this test, we consider the call to Render a sign
209   // of success and quit the loop.
210   if (synchronized_io_) {
211     // For synchronized I/O, we expect RenderIO().
212     EXPECT_CALL(callback_, RenderIO(_, _, _))
213         .WillOnce(QuitLoop(io_loop_.message_loop_proxy()));
214   } else {
215     // For output only we expect Render().
216     const int kNumberOfFramesToProcess = 0;
217     EXPECT_CALL(callback_, Render(_, _))
218         .WillOnce(DoAll(
219             QuitLoop(io_loop_.message_loop_proxy()),
220             Return(kNumberOfFramesToProcess)));
221   }
222 }
223
224 void AudioOutputDeviceTest::WaitUntilRenderCallback() {
225   // Don't hang the test if we never get the Render() callback.
226   io_loop_.PostDelayedTask(FROM_HERE, base::MessageLoop::QuitClosure(),
227                            TestTimeouts::action_timeout());
228   io_loop_.Run();
229 }
230
231 void AudioOutputDeviceTest::StopAudioDevice() {
232   audio_device_->Stop();
233
234   EXPECT_CALL(*audio_output_ipc_, CloseStream());
235
236   io_loop_.RunUntilIdle();
237 }
238
239 TEST_P(AudioOutputDeviceTest, Initialize) {
240   // Tests that the object can be constructed, initialized and destructed
241   // without having ever been started/stopped.
242 }
243
244 // Calls Start() followed by an immediate Stop() and check for the basic message
245 // filter messages being sent in that case.
246 TEST_P(AudioOutputDeviceTest, StartStop) {
247   StartAudioDevice();
248   StopAudioDevice();
249 }
250
251 // AudioOutputDevice supports multiple start/stop sequences.
252 TEST_P(AudioOutputDeviceTest, StartStopStartStop) {
253   StartAudioDevice();
254   StopAudioDevice();
255   StartAudioDevice();
256   StopAudioDevice();
257 }
258
259 // Simulate receiving OnStreamCreated() prior to processing ShutDownOnIOThread()
260 // on the IO loop.
261 TEST_P(AudioOutputDeviceTest, StopBeforeRender) {
262   StartAudioDevice();
263
264   // Call Stop() but don't run the IO loop yet.
265   audio_device_->Stop();
266
267   // Expect us to shutdown IPC but not to render anything despite the stream
268   // getting created.
269   EXPECT_CALL(*audio_output_ipc_, CloseStream());
270   CreateStream();
271 }
272
273 // Full test with output only.
274 TEST_P(AudioOutputDeviceTest, CreateStream) {
275   StartAudioDevice();
276   ExpectRenderCallback();
277   CreateStream();
278   WaitUntilRenderCallback();
279   StopAudioDevice();
280 }
281
282 INSTANTIATE_TEST_CASE_P(Render, AudioOutputDeviceTest, Values(false));
283 INSTANTIATE_TEST_CASE_P(RenderIO, AudioOutputDeviceTest, Values(true));
284
285 }  // namespace media.