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