OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 <vector> | 5 #include <vector> |
6 | 6 |
7 #include "base/at_exit.h" | 7 #include "base/at_exit.h" |
8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
9 #include "base/process_util.h" | 9 #include "base/process_util.h" |
10 #include "base/shared_memory.h" | 10 #include "base/shared_memory.h" |
11 #include "base/sync_socket.h" | 11 #include "base/sync_socket.h" |
12 #include "base/test/test_timeouts.h" | 12 #include "base/test/test_timeouts.h" |
13 #include "content/common/media/audio_messages.h" | 13 #include "media/audio/audio_output_device.h" |
14 #include "content/renderer/media/audio_device.h" | |
15 #include "content/renderer/media/audio_message_filter.h" | |
16 #include "media/audio/audio_util.h" | 14 #include "media/audio/audio_util.h" |
17 #include "media/audio/sample_rates.h" | 15 #include "media/audio/sample_rates.h" |
18 #include "testing/gmock/include/gmock/gmock.h" | 16 #include "testing/gmock/include/gmock/gmock.h" |
19 #include "testing/gmock_mutant.h" | 17 #include "testing/gmock_mutant.h" |
20 #include "testing/gtest/include/gtest/gtest.h" | 18 #include "testing/gtest/include/gtest/gtest.h" |
21 | 19 |
22 using base::CancelableSyncSocket; | 20 using base::CancelableSyncSocket; |
23 using base::SharedMemory; | 21 using base::SharedMemory; |
24 using base::SyncSocket; | 22 using base::SyncSocket; |
25 using testing::_; | 23 using testing::_; |
26 using testing::DoAll; | 24 using testing::DoAll; |
27 using testing::Invoke; | 25 using testing::Invoke; |
28 using testing::Return; | 26 using testing::Return; |
29 using testing::WithArgs; | 27 using testing::WithArgs; |
30 | 28 |
| 29 namespace media { |
| 30 |
31 namespace { | 31 namespace { |
32 | 32 |
33 class MockRenderCallback : public media::AudioRendererSink::RenderCallback { | 33 class MockRenderCallback : public AudioRendererSink::RenderCallback { |
34 public: | 34 public: |
35 MockRenderCallback() {} | 35 MockRenderCallback() {} |
36 virtual ~MockRenderCallback() {} | 36 virtual ~MockRenderCallback() {} |
37 | 37 |
38 MOCK_METHOD3(Render, int(const std::vector<float*>& audio_data, | 38 MOCK_METHOD3(Render, int(const std::vector<float*>& audio_data, |
39 int number_of_frames, | 39 int number_of_frames, |
40 int audio_delay_milliseconds)); | 40 int audio_delay_milliseconds)); |
41 MOCK_METHOD0(OnRenderError, void()); | 41 MOCK_METHOD0(OnRenderError, void()); |
42 }; | 42 }; |
43 | 43 |
44 class MockAudioMessageFilter : public AudioMessageFilter { | 44 class MockAudioOutputIPC : public AudioOutputIPC { |
45 public: | 45 public: |
46 MockAudioMessageFilter() {} | 46 MockAudioOutputIPC() {} |
| 47 virtual ~MockAudioOutputIPC() {} |
| 48 |
| 49 MOCK_METHOD1(AddDelegate, int(AudioOutputIPCDelegate* delegate)); |
| 50 MOCK_METHOD1(RemoveDelegate, void(int stream_id)); |
47 | 51 |
48 MOCK_METHOD2(CreateStream, | 52 MOCK_METHOD2(CreateStream, |
49 void(int stream_id, const media::AudioParameters& params)); | 53 void(int stream_id, const AudioParameters& params)); |
50 MOCK_METHOD1(PlayStream, void(int stream_id)); | 54 MOCK_METHOD1(PlayStream, void(int stream_id)); |
51 MOCK_METHOD1(CloseStream, void(int stream_id)); | 55 MOCK_METHOD1(CloseStream, void(int stream_id)); |
52 MOCK_METHOD2(SetVolume, void(int stream_id, double volume)); | 56 MOCK_METHOD2(SetVolume, void(int stream_id, double volume)); |
53 MOCK_METHOD1(PauseStream, void(int stream_id)); | 57 MOCK_METHOD1(PauseStream, void(int stream_id)); |
54 MOCK_METHOD1(FlushStream, void(int stream_id)); | 58 MOCK_METHOD1(FlushStream, void(int stream_id)); |
55 | |
56 protected: | |
57 virtual ~MockAudioMessageFilter() {} | |
58 }; | 59 }; |
59 | 60 |
60 // Creates a copy of a SyncSocket handle that we can give to AudioDevice. | 61 // Creates a copy of a SyncSocket handle that we can give to AudioOutputDevice. |
61 // On Windows this means duplicating the pipe handle so that AudioDevice can | 62 // On Windows this means duplicating the pipe handle so that AudioOutputDevice |
62 // call CloseHandle() (since ownership has been transferred), but on other | 63 // can call CloseHandle() (since ownership has been transferred), but on other |
63 // platforms, we just copy the same socket handle since AudioDevice on those | 64 // platforms, we just copy the same socket handle since AudioOutputDevice on |
64 // platforms won't actually own the socket (FileDescriptor.auto_close is false). | 65 // those platforms won't actually own the socket (FileDescriptor.auto_close is |
| 66 // false). |
65 bool DuplicateSocketHandle(SyncSocket::Handle socket_handle, | 67 bool DuplicateSocketHandle(SyncSocket::Handle socket_handle, |
66 SyncSocket::Handle* copy) { | 68 SyncSocket::Handle* copy) { |
67 #if defined(OS_WIN) | 69 #if defined(OS_WIN) |
68 HANDLE process = GetCurrentProcess(); | 70 HANDLE process = GetCurrentProcess(); |
69 ::DuplicateHandle(process, socket_handle, process, copy, | 71 ::DuplicateHandle(process, socket_handle, process, copy, |
70 0, FALSE, DUPLICATE_SAME_ACCESS); | 72 0, FALSE, DUPLICATE_SAME_ACCESS); |
71 return *copy != NULL; | 73 return *copy != NULL; |
72 #else | 74 #else |
73 *copy = socket_handle; | 75 *copy = socket_handle; |
74 return *copy != -1; | 76 return *copy != -1; |
(...skipping 18 matching lines...) Expand all Loading... |
93 for (; it != audio_data.end(); ++it) { | 95 for (; it != audio_data.end(); ++it) { |
94 float* channel = *it; | 96 float* channel = *it; |
95 for (int j = 0; j < number_of_frames; ++j) { | 97 for (int j = 0; j < number_of_frames; ++j) { |
96 channel[j] = 0.0f; | 98 channel[j] = 0.0f; |
97 } | 99 } |
98 } | 100 } |
99 } | 101 } |
100 | 102 |
101 } // namespace. | 103 } // namespace. |
102 | 104 |
103 class AudioDeviceTest : public testing::Test { | 105 class AudioOutputDeviceTest : public testing::Test { |
104 public: | 106 public: |
105 AudioDeviceTest() | 107 AudioOutputDeviceTest() |
106 : default_audio_parameters_(media::AudioParameters::AUDIO_PCM_LINEAR, | 108 : default_audio_parameters_(AudioParameters::AUDIO_PCM_LINEAR, |
107 CHANNEL_LAYOUT_STEREO, | 109 CHANNEL_LAYOUT_STEREO, |
108 48000, 16, 1024), | 110 48000, 16, 1024), |
109 stream_id_(-1) { | 111 stream_id_(-1) { |
110 } | 112 } |
111 | 113 |
112 ~AudioDeviceTest() {} | 114 ~AudioOutputDeviceTest() {} |
113 | 115 |
114 virtual void SetUp() OVERRIDE { | 116 AudioOutputDevice* CreateAudioDevice() { |
115 // This sets a global audio_message_filter pointer. AudioDevice will pick | 117 return new AudioOutputDevice( |
116 // up a pointer to this variable via the static AudioMessageFilter::Get() | 118 &audio_output_ipc_, io_loop_.message_loop_proxy()); |
117 // method. | |
118 audio_message_filter_ = new MockAudioMessageFilter(); | |
119 } | |
120 | |
121 AudioDevice* CreateAudioDevice() { | |
122 return new AudioDevice( | |
123 audio_message_filter_, io_loop_.message_loop_proxy()); | |
124 } | 119 } |
125 | 120 |
126 void set_stream_id(int stream_id) { stream_id_ = stream_id; } | 121 void set_stream_id(int stream_id) { stream_id_ = stream_id; } |
127 | 122 |
128 protected: | 123 protected: |
129 // Used to clean up TLS pointers that the test(s) will initialize. | 124 // Used to clean up TLS pointers that the test(s) will initialize. |
130 // Must remain the first member of this class. | 125 // Must remain the first member of this class. |
131 base::ShadowingAtExitManager at_exit_manager_; | 126 base::ShadowingAtExitManager at_exit_manager_; |
132 MessageLoopForIO io_loop_; | 127 MessageLoopForIO io_loop_; |
133 const media::AudioParameters default_audio_parameters_; | 128 const AudioParameters default_audio_parameters_; |
134 MockRenderCallback callback_; | 129 MockRenderCallback callback_; |
135 scoped_refptr<MockAudioMessageFilter> audio_message_filter_; | 130 MockAudioOutputIPC audio_output_ipc_; |
136 int stream_id_; | 131 int stream_id_; |
137 }; | 132 }; |
138 | 133 |
139 // The simplest test for AudioDevice. Used to test construction of AudioDevice | 134 // The simplest test for AudioOutputDevice. Used to test construction of |
140 // and that the runtime environment is set up correctly. | 135 // AudioOutputDevice and that the runtime environment is set up correctly. |
141 TEST_F(AudioDeviceTest, Initialize) { | 136 TEST_F(AudioOutputDeviceTest, Initialize) { |
142 scoped_refptr<AudioDevice> audio_device(CreateAudioDevice()); | 137 scoped_refptr<AudioOutputDevice> audio_device(CreateAudioDevice()); |
143 audio_device->Initialize(default_audio_parameters_, &callback_); | 138 audio_device->Initialize(default_audio_parameters_, &callback_); |
144 io_loop_.RunAllPending(); | 139 io_loop_.RunAllPending(); |
145 } | 140 } |
146 | 141 |
147 // Calls Start() followed by an immediate Stop() and check for the basic message | 142 // Calls Start() followed by an immediate Stop() and check for the basic message |
148 // filter messages being sent in that case. | 143 // filter messages being sent in that case. |
149 TEST_F(AudioDeviceTest, StartStop) { | 144 TEST_F(AudioOutputDeviceTest, StartStop) { |
150 scoped_refptr<AudioDevice> audio_device(CreateAudioDevice()); | 145 scoped_refptr<AudioOutputDevice> audio_device(CreateAudioDevice()); |
151 audio_device->Initialize(default_audio_parameters_, &callback_); | 146 audio_device->Initialize(default_audio_parameters_, &callback_); |
152 | 147 |
| 148 EXPECT_CALL(audio_output_ipc_, AddDelegate(audio_device.get())) |
| 149 .WillOnce(Return(1)); |
| 150 EXPECT_CALL(audio_output_ipc_, RemoveDelegate(1)).WillOnce(Return()); |
| 151 |
153 audio_device->Start(); | 152 audio_device->Start(); |
154 audio_device->Stop(); | 153 audio_device->Stop(); |
155 | 154 |
156 EXPECT_CALL(*audio_message_filter_, CreateStream(_, _)); | 155 EXPECT_CALL(audio_output_ipc_, CreateStream(_, _)); |
157 EXPECT_CALL(*audio_message_filter_, CloseStream(_)); | 156 EXPECT_CALL(audio_output_ipc_, CloseStream(_)); |
158 | 157 |
159 io_loop_.RunAllPending(); | 158 io_loop_.RunAllPending(); |
160 } | 159 } |
161 | 160 |
162 // Starts an audio stream, creates a shared memory section + SyncSocket pair | 161 // Starts an audio stream, creates a shared memory section + SyncSocket pair |
163 // that AudioDevice must use for audio data. It then sends a request for | 162 // that AudioOutputDevice must use for audio data. It then sends a request for |
164 // a single audio packet and quits when the packet has been sent. | 163 // a single audio packet and quits when the packet has been sent. |
165 TEST_F(AudioDeviceTest, CreateStream) { | 164 TEST_F(AudioOutputDeviceTest, CreateStream) { |
166 scoped_refptr<AudioDevice> audio_device(CreateAudioDevice()); | 165 scoped_refptr<AudioOutputDevice> audio_device(CreateAudioDevice()); |
167 audio_device->Initialize(default_audio_parameters_, &callback_); | 166 audio_device->Initialize(default_audio_parameters_, &callback_); |
168 | 167 |
| 168 EXPECT_CALL(audio_output_ipc_, AddDelegate(audio_device.get())) |
| 169 .WillOnce(Return(1)); |
| 170 EXPECT_CALL(audio_output_ipc_, RemoveDelegate(1)).WillOnce(Return()); |
| 171 |
169 audio_device->Start(); | 172 audio_device->Start(); |
170 | 173 |
171 EXPECT_CALL(*audio_message_filter_, CreateStream(_, _)) | 174 EXPECT_CALL(audio_output_ipc_, CreateStream(_, _)) |
172 .WillOnce(WithArgs<0>(Invoke(this, &AudioDeviceTest::set_stream_id))); | 175 .WillOnce(WithArgs<0>( |
| 176 Invoke(this, &AudioOutputDeviceTest::set_stream_id))); |
| 177 |
173 | 178 |
174 EXPECT_EQ(stream_id_, -1); | 179 EXPECT_EQ(stream_id_, -1); |
175 io_loop_.RunAllPending(); | 180 io_loop_.RunAllPending(); |
176 | 181 |
177 // OnCreateStream() must have been called and we should have a valid | 182 // OnCreateStream() must have been called and we should have a valid |
178 // stream id. | 183 // stream id. |
179 ASSERT_NE(stream_id_, -1); | 184 ASSERT_NE(stream_id_, -1); |
180 | 185 |
181 // This is where it gets a bit hacky. The shared memory contract between | 186 // This is where it gets a bit hacky. The shared memory contract between |
182 // AudioDevice and its browser side counter part includes a bit more than | 187 // AudioOutputDevice and its browser side counter part includes a bit more |
183 // just the audio data, so we must call TotalSharedMemorySizeInBytes() to get | 188 // than just the audio data, so we must call TotalSharedMemorySizeInBytes() |
184 // the actual size needed to fit the audio data plus the extra data. | 189 // to get the actual size needed to fit the audio data plus the extra data. |
185 int memory_size = media::TotalSharedMemorySizeInBytes( | 190 int memory_size = TotalSharedMemorySizeInBytes( |
186 default_audio_parameters_.GetBytesPerBuffer()); | 191 default_audio_parameters_.GetBytesPerBuffer()); |
187 SharedMemory shared_memory; | 192 SharedMemory shared_memory; |
188 ASSERT_TRUE(shared_memory.CreateAndMapAnonymous(memory_size)); | 193 ASSERT_TRUE(shared_memory.CreateAndMapAnonymous(memory_size)); |
189 memset(shared_memory.memory(), 0xff, memory_size); | 194 memset(shared_memory.memory(), 0xff, memory_size); |
190 | 195 |
191 CancelableSyncSocket browser_socket, renderer_socket; | 196 CancelableSyncSocket browser_socket, renderer_socket; |
192 ASSERT_TRUE(CancelableSyncSocket::CreatePair(&browser_socket, | 197 ASSERT_TRUE(CancelableSyncSocket::CreatePair(&browser_socket, |
193 &renderer_socket)); | 198 &renderer_socket)); |
194 | 199 |
195 // Create duplicates of the handles we pass to AudioDevice since ownership | 200 // Create duplicates of the handles we pass to AudioOutputDevice since |
196 // will be transferred and AudioDevice is responsible for freeing. | 201 // ownership will be transferred and AudioOutputDevice is responsible for |
| 202 // freeing. |
197 SyncSocket::Handle audio_device_socket = SyncSocket::kInvalidHandle; | 203 SyncSocket::Handle audio_device_socket = SyncSocket::kInvalidHandle; |
198 ASSERT_TRUE(DuplicateSocketHandle(renderer_socket.handle(), | 204 ASSERT_TRUE(DuplicateSocketHandle(renderer_socket.handle(), |
199 &audio_device_socket)); | 205 &audio_device_socket)); |
200 base::SharedMemoryHandle duplicated_memory_handle; | 206 base::SharedMemoryHandle duplicated_memory_handle; |
201 ASSERT_TRUE(shared_memory.ShareToProcess(base::GetCurrentProcessHandle(), | 207 ASSERT_TRUE(shared_memory.ShareToProcess(base::GetCurrentProcessHandle(), |
202 &duplicated_memory_handle)); | 208 &duplicated_memory_handle)); |
203 | 209 |
204 // We should get a 'play' notification when we call OnStreamCreated(). | 210 // We should get a 'play' notification when we call OnStreamCreated(). |
205 // Respond by asking for some audio data. This should ask our callback | 211 // Respond by asking for some audio data. This should ask our callback |
206 // to provide some audio data that AudioDevice then writes into the shared | 212 // to provide some audio data that AudioOutputDevice then writes into the |
207 // memory section. | 213 // shared memory section. |
208 EXPECT_CALL(*audio_message_filter_, PlayStream(stream_id_)) | 214 EXPECT_CALL(audio_output_ipc_, PlayStream(stream_id_)) |
209 .WillOnce(SendPendingBytes(&browser_socket, memory_size)); | 215 .WillOnce(SendPendingBytes(&browser_socket, memory_size)); |
210 | 216 |
211 // We expect calls to our audio renderer callback, which returns the number | 217 // We expect calls to our audio renderer callback, which returns the number |
212 // of frames written to the memory section. | 218 // of frames written to the memory section. |
213 // Here's the second place where it gets hacky: There's no way for us to | 219 // Here's the second place where it gets hacky: There's no way for us to |
214 // know (without using a sleep loop!) when the AudioDevice has finished | 220 // know (without using a sleep loop!) when the AudioOutputDevice has finished |
215 // writing the interleaved audio data into the shared memory section. | 221 // writing the interleaved audio data into the shared memory section. |
216 // So, for the sake of this test, we consider the call to Render a sign | 222 // So, for the sake of this test, we consider the call to Render a sign |
217 // of success and quit the loop. | 223 // of success and quit the loop. |
218 | 224 |
219 // A note on the call to ZeroAudioData(): | 225 // A note on the call to ZeroAudioData(): |
220 // Valgrind caught a bug in AudioDevice::AudioThreadCallback::Process() | 226 // Valgrind caught a bug in AudioOutputDevice::AudioThreadCallback::Process() |
221 // whereby we always interleaved all the frames in the buffer regardless | 227 // whereby we always interleaved all the frames in the buffer regardless |
222 // of how many were actually rendered. So to keep the benefits of that | 228 // of how many were actually rendered. So to keep the benefits of that |
223 // test, we explicitly pass 0 in here as the number of frames to | 229 // test, we explicitly pass 0 in here as the number of frames to |
224 // ZeroAudioData(). Other tests might want to pass the requested number | 230 // ZeroAudioData(). Other tests might want to pass the requested number |
225 // by using WithArgs<1, 0>(Invoke(&ZeroAudioData)) and set the return | 231 // by using WithArgs<1, 0>(Invoke(&ZeroAudioData)) and set the return |
226 // value accordingly. | 232 // value accordingly. |
227 const int kNumberOfFramesToProcess = 0; | 233 const int kNumberOfFramesToProcess = 0; |
228 | 234 |
229 EXPECT_CALL(callback_, Render(_, _, _)) | 235 EXPECT_CALL(callback_, Render(_, _, _)) |
230 .WillOnce(DoAll( | 236 .WillOnce(DoAll( |
231 WithArgs<0>(Invoke( | 237 WithArgs<0>(Invoke( |
232 testing::CreateFunctor(&ZeroAudioData, | 238 testing::CreateFunctor(&ZeroAudioData, |
233 kNumberOfFramesToProcess))), | 239 kNumberOfFramesToProcess))), |
234 QuitLoop(io_loop_.message_loop_proxy()), | 240 QuitLoop(io_loop_.message_loop_proxy()), |
235 Return(kNumberOfFramesToProcess))); | 241 Return(kNumberOfFramesToProcess))); |
236 | 242 |
237 audio_device->OnStreamCreated(duplicated_memory_handle, audio_device_socket, | 243 audio_device->OnStreamCreated(duplicated_memory_handle, audio_device_socket, |
238 memory_size); | 244 memory_size); |
239 | 245 |
240 io_loop_.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), | 246 io_loop_.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), |
241 TestTimeouts::action_timeout()); | 247 TestTimeouts::action_timeout()); |
242 io_loop_.Run(); | 248 io_loop_.Run(); |
243 | 249 |
244 // Close the stream sequence. | 250 // Close the stream sequence. |
245 EXPECT_CALL(*audio_message_filter_, CloseStream(stream_id_)); | 251 EXPECT_CALL(audio_output_ipc_, CloseStream(stream_id_)); |
246 | 252 |
247 audio_device->Stop(); | 253 audio_device->Stop(); |
248 io_loop_.RunAllPending(); | 254 io_loop_.RunAllPending(); |
249 } | 255 } |
| 256 |
| 257 } // namespace media. |
OLD | NEW |