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

Side by Side Diff: content/renderer/media/audio_device_unittest.cc

Issue 10834033: Move AudioDevice and AudioInputDevice to media. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed comments and fixed a few lint issues Created 8 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 | Annotate | Revision Log
OLDNEW
(Empty)
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/message_loop.h"
9 #include "base/process_util.h"
10 #include "base/shared_memory.h"
11 #include "base/sync_socket.h"
12 #include "base/test/test_timeouts.h"
13 #include "content/common/media/audio_messages.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"
17 #include "media/audio/sample_rates.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gmock_mutant.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 using base::CancelableSyncSocket;
23 using base::SharedMemory;
24 using base::SyncSocket;
25 using testing::_;
26 using testing::DoAll;
27 using testing::Invoke;
28 using testing::Return;
29 using testing::WithArgs;
30
31 namespace {
32
33 class MockRenderCallback : public media::AudioRendererSink::RenderCallback {
34 public:
35 MockRenderCallback() {}
36 virtual ~MockRenderCallback() {}
37
38 MOCK_METHOD3(Render, int(const std::vector<float*>& audio_data,
39 int number_of_frames,
40 int audio_delay_milliseconds));
41 MOCK_METHOD0(OnRenderError, void());
42 };
43
44 class MockAudioMessageFilter : public AudioMessageFilter {
45 public:
46 MockAudioMessageFilter() {}
47
48 MOCK_METHOD2(CreateStream,
49 void(int stream_id, const media::AudioParameters& params));
50 MOCK_METHOD1(PlayStream, void(int stream_id));
51 MOCK_METHOD1(CloseStream, void(int stream_id));
52 MOCK_METHOD2(SetVolume, void(int stream_id, double volume));
53 MOCK_METHOD1(PauseStream, void(int stream_id));
54 MOCK_METHOD1(FlushStream, void(int stream_id));
55
56 protected:
57 virtual ~MockAudioMessageFilter() {}
58 };
59
60 // Creates a copy of a SyncSocket handle that we can give to AudioDevice.
61 // On Windows this means duplicating the pipe handle so that AudioDevice can
62 // 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 won't actually own the socket (FileDescriptor.auto_close is false).
65 bool DuplicateSocketHandle(SyncSocket::Handle socket_handle,
66 SyncSocket::Handle* copy) {
67 #if defined(OS_WIN)
68 HANDLE process = GetCurrentProcess();
69 ::DuplicateHandle(process, socket_handle, process, copy,
70 0, FALSE, DUPLICATE_SAME_ACCESS);
71 return *copy != NULL;
72 #else
73 *copy = socket_handle;
74 return *copy != -1;
75 #endif
76 }
77
78 ACTION_P2(SendPendingBytes, socket, pending_bytes) {
79 socket->Send(&pending_bytes, sizeof(pending_bytes));
80 }
81
82 // Used to terminate a loop from a different thread than the loop belongs to.
83 // |loop| should be a MessageLoopProxy.
84 ACTION_P(QuitLoop, loop) {
85 loop->PostTask(FROM_HERE, MessageLoop::QuitClosure());
86 }
87
88 // Zeros out |number_of_frames| in all channel buffers pointed to by
89 // the |audio_data| vector.
90 void ZeroAudioData(int number_of_frames,
91 const std::vector<float*>& audio_data) {
92 std::vector<float*>::const_iterator it = audio_data.begin();
93 for (; it != audio_data.end(); ++it) {
94 float* channel = *it;
95 for (int j = 0; j < number_of_frames; ++j) {
96 channel[j] = 0.0f;
97 }
98 }
99 }
100
101 } // namespace.
102
103 class AudioDeviceTest : public testing::Test {
104 public:
105 AudioDeviceTest()
106 : default_audio_parameters_(media::AudioParameters::AUDIO_PCM_LINEAR,
107 CHANNEL_LAYOUT_STEREO,
108 48000, 16, 1024),
109 stream_id_(-1) {
110 }
111
112 ~AudioDeviceTest() {}
113
114 virtual void SetUp() OVERRIDE {
115 // This sets a global audio_message_filter pointer. AudioDevice will pick
116 // up a pointer to this variable via the static AudioMessageFilter::Get()
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 }
125
126 void set_stream_id(int stream_id) { stream_id_ = stream_id; }
127
128 protected:
129 // Used to clean up TLS pointers that the test(s) will initialize.
130 // Must remain the first member of this class.
131 base::ShadowingAtExitManager at_exit_manager_;
132 MessageLoopForIO io_loop_;
133 const media::AudioParameters default_audio_parameters_;
134 MockRenderCallback callback_;
135 scoped_refptr<MockAudioMessageFilter> audio_message_filter_;
136 int stream_id_;
137 };
138
139 // The simplest test for AudioDevice. Used to test construction of AudioDevice
140 // and that the runtime environment is set up correctly.
141 TEST_F(AudioDeviceTest, Initialize) {
142 scoped_refptr<AudioDevice> audio_device(CreateAudioDevice());
143 audio_device->Initialize(default_audio_parameters_, &callback_);
144 io_loop_.RunAllPending();
145 }
146
147 // Calls Start() followed by an immediate Stop() and check for the basic message
148 // filter messages being sent in that case.
149 TEST_F(AudioDeviceTest, StartStop) {
150 scoped_refptr<AudioDevice> audio_device(CreateAudioDevice());
151 audio_device->Initialize(default_audio_parameters_, &callback_);
152
153 audio_device->Start();
154 audio_device->Stop();
155
156 EXPECT_CALL(*audio_message_filter_, CreateStream(_, _));
157 EXPECT_CALL(*audio_message_filter_, CloseStream(_));
158
159 io_loop_.RunAllPending();
160 }
161
162 // 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
164 // a single audio packet and quits when the packet has been sent.
165 TEST_F(AudioDeviceTest, CreateStream) {
166 scoped_refptr<AudioDevice> audio_device(CreateAudioDevice());
167 audio_device->Initialize(default_audio_parameters_, &callback_);
168
169 audio_device->Start();
170
171 EXPECT_CALL(*audio_message_filter_, CreateStream(_, _))
172 .WillOnce(WithArgs<0>(Invoke(this, &AudioDeviceTest::set_stream_id)));
173
174 EXPECT_EQ(stream_id_, -1);
175 io_loop_.RunAllPending();
176
177 // OnCreateStream() must have been called and we should have a valid
178 // stream id.
179 ASSERT_NE(stream_id_, -1);
180
181 // 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
183 // just the audio data, so we must call TotalSharedMemorySizeInBytes() to get
184 // the actual size needed to fit the audio data plus the extra data.
185 int memory_size = media::TotalSharedMemorySizeInBytes(
186 default_audio_parameters_.GetBytesPerBuffer());
187 SharedMemory shared_memory;
188 ASSERT_TRUE(shared_memory.CreateAndMapAnonymous(memory_size));
189 memset(shared_memory.memory(), 0xff, memory_size);
190
191 CancelableSyncSocket browser_socket, renderer_socket;
192 ASSERT_TRUE(CancelableSyncSocket::CreatePair(&browser_socket,
193 &renderer_socket));
194
195 // Create duplicates of the handles we pass to AudioDevice since ownership
196 // will be transferred and AudioDevice is responsible for freeing.
197 SyncSocket::Handle audio_device_socket = SyncSocket::kInvalidHandle;
198 ASSERT_TRUE(DuplicateSocketHandle(renderer_socket.handle(),
199 &audio_device_socket));
200 base::SharedMemoryHandle duplicated_memory_handle;
201 ASSERT_TRUE(shared_memory.ShareToProcess(base::GetCurrentProcessHandle(),
202 &duplicated_memory_handle));
203
204 // We should get a 'play' notification when we call OnStreamCreated().
205 // 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
207 // memory section.
208 EXPECT_CALL(*audio_message_filter_, PlayStream(stream_id_))
209 .WillOnce(SendPendingBytes(&browser_socket, memory_size));
210
211 // We expect calls to our audio renderer callback, which returns the number
212 // of frames written to the memory section.
213 // 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
215 // 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
217 // of success and quit the loop.
218
219 // A note on the call to ZeroAudioData():
220 // Valgrind caught a bug in AudioDevice::AudioThreadCallback::Process()
221 // 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
223 // test, we explicitly pass 0 in here as the number of frames to
224 // ZeroAudioData(). Other tests might want to pass the requested number
225 // by using WithArgs<1, 0>(Invoke(&ZeroAudioData)) and set the return
226 // value accordingly.
227 const int kNumberOfFramesToProcess = 0;
228
229 EXPECT_CALL(callback_, Render(_, _, _))
230 .WillOnce(DoAll(
231 WithArgs<0>(Invoke(
232 testing::CreateFunctor(&ZeroAudioData,
233 kNumberOfFramesToProcess))),
234 QuitLoop(io_loop_.message_loop_proxy()),
235 Return(kNumberOfFramesToProcess)));
236
237 audio_device->OnStreamCreated(duplicated_memory_handle, audio_device_socket,
238 memory_size);
239
240 io_loop_.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(),
241 TestTimeouts::action_timeout());
242 io_loop_.Run();
243
244 // Close the stream sequence.
245 EXPECT_CALL(*audio_message_filter_, CloseStream(stream_id_));
246
247 audio_device->Stop();
248 io_loop_.RunAllPending();
249 }
OLDNEW
« no previous file with comments | « content/renderer/media/audio_device_thread.cc ('k') | content/renderer/media/audio_input_device.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698