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

Side by Side Diff: media/audio/audio_power_monitor_unittest.cc

Issue 14600025: Replace AudioSilenceDetector with an AudioPowerMonitor. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Better handling of bad AudioBus data. Minor tweaks. Created 7 years, 7 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) 2013 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 "media/audio/audio_power_monitor.h"
6
7 #include <cmath>
8 #include <limits>
9
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/message_loop.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/threading/thread.h"
15 #include "base/time.h"
16 #include "media/base/audio_bus.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 using ::testing::_;
21 using ::testing::FloatEq;
22 using ::testing::InvokeWithoutArgs;
23 using ::testing::TestWithParam;
24 using ::testing::Values;
25
26 namespace media {
27
28 static const int kSampleRate = 48000;
29 static const int kFramesPerBuffer = 128;
30
31 namespace {
32
33 class MockObserver {
34 public:
35 MOCK_METHOD1(OnPowerMeasured, void(float));
36 };
37
38 struct TestScenario {
39 const float* data;
40 int num_channels;
41 int num_frames;
42 float power_in_dbfs;
43
44 TestScenario(const float* d, int c, int f, float p)
45 : data(d), num_channels(c), num_frames(f), power_in_dbfs(p) {}
46 };
47
48 } // namespace
49
50 class AudioPowerMonitorTest : public TestWithParam<TestScenario> {
51 public:
52 AudioPowerMonitorTest()
53 : audio_manager_thread_(new base::Thread("AudioThread")),
54 notification_received_(false, false) {
55 audio_manager_thread_->Start();
56 audio_message_loop_ = audio_manager_thread_->message_loop_proxy();
57 }
58
59 virtual ~AudioPowerMonitorTest() {
60 SyncWithAudioThread();
61 }
62
63 AudioPowerMonitor* power_monitor() const {
64 return power_monitor_.get();
65 }
66
67 void StartPowerMonitor(MockObserver* observer) {
68 audio_message_loop_->PostTask(
69 FROM_HERE,
70 base::Bind(&AudioPowerMonitorTest::StartMonitorOnAudioThread,
71 base::Unretained(this), observer));
72 SyncWithAudioThread();
73 }
74
75 void StopPowerMonitor() {
76 audio_message_loop_->PostTask(
77 FROM_HERE,
78 base::Bind(&AudioPowerMonitorTest::StopMonitorOnAudioThread,
79 base::Unretained(this)));
80 SyncWithAudioThread();
81 }
82
83 // Creates an AudioBus, sized and populated with kFramesPerBuffer frames of
84 // data. The given test |data| is repeated to fill the buffer.
85 scoped_ptr<AudioBus> CreatePopulatedBuffer(
86 const float* data, int num_channels, int num_frames) {
87 scoped_ptr<AudioBus> bus = AudioBus::Create(num_channels, kFramesPerBuffer);
88 for (int ch = 0; ch < num_channels; ++ch) {
89 for (int frames = 0; frames < kFramesPerBuffer; frames += num_frames) {
90 const int num_to_copy = std::min(num_frames, kFramesPerBuffer - frames);
91 memcpy(bus->channel(ch) + frames, data + num_frames * ch,
92 sizeof(float) * num_to_copy);
93 }
94 }
95 return bus.Pass();
96 }
97
98 scoped_ptr<AudioBus> CreateZeroedBuffer(int num_channels) {
99 scoped_ptr<AudioBus> bus = AudioBus::Create(num_channels, kFramesPerBuffer);
100 bus->Zero();
101 return bus.Pass();
102 }
103
104
105 void SignalNotificationReceived() {
106 notification_received_.Signal();
107 }
108
109 void WaitForNotificationReceived() {
110 notification_received_.Wait();
111 }
112
113 // Post a task on the audio thread and block until it is executed. This
114 // provides a barrier: All previous tasks pending on the audio thread have
115 // completed before this method returns.
116 void SyncWithAudioThread() {
117 base::WaitableEvent done(false, false);
118 audio_message_loop_->PostTask(
119 FROM_HERE,
120 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
121 done.Wait();
122 }
123
124 private:
125 void StartMonitorOnAudioThread(MockObserver* observer) {
126 const AudioPowerMonitor::PowerMeasurementCallback callback =
127 base::Bind(&MockObserver::OnPowerMeasured, base::Unretained(observer));
128 power_monitor_.reset(new AudioPowerMonitor(
129 kSampleRate, base::TimeDelta::FromMilliseconds(1),
130 MessageLoop::current(), callback));
131 }
132
133 void StopMonitorOnAudioThread() {
134 power_monitor_.reset();
135 }
136
137 scoped_ptr<base::Thread> audio_manager_thread_;
138 scoped_refptr<base::MessageLoopProxy> audio_message_loop_;
139
140 base::WaitableEvent notification_received_;
141
142 scoped_ptr<AudioPowerMonitor> power_monitor_;
143
144 DISALLOW_COPY_AND_ASSIGN(AudioPowerMonitorTest);
145 };
146
147 TEST_P(AudioPowerMonitorTest, MeasuresPowerOfSignal) {
148 const TestScenario& scenario = GetParam();
149
150 MockObserver observer;
151 StartPowerMonitor(&observer);
152
153 // Send silence and expect a callback with a "zero power" result.
154 EXPECT_CALL(observer,
155 OnPowerMeasured(FloatEq(AudioPowerMonitor::kZeroPowerDBFS)))
156 .WillOnce(InvokeWithoutArgs(
157 this, &AudioPowerMonitorTest::SignalNotificationReceived))
158 .RetiresOnSaturation();
159 scoped_ptr<AudioBus> bus = CreateZeroedBuffer(scenario.num_channels);
160 power_monitor()->Scan(*bus, bus->frames());
161 WaitForNotificationReceived();
162
163 // Send audio signal data to the power monitor and expect a callback with the
164 // correct result.
165 EXPECT_CALL(observer, OnPowerMeasured(FloatEq(scenario.power_in_dbfs)))
166 .WillOnce(InvokeWithoutArgs(
167 this, &AudioPowerMonitorTest::SignalNotificationReceived))
168 .RetiresOnSaturation();
169 bus = CreatePopulatedBuffer(
170 scenario.data, scenario.num_channels, scenario.num_frames);
171 power_monitor()->Scan(*bus, bus->frames());
172 WaitForNotificationReceived();
173
174 // Send silence again and expect a callback with a "zero power" result again.
175 EXPECT_CALL(observer,
176 OnPowerMeasured(FloatEq(AudioPowerMonitor::kZeroPowerDBFS)))
177 .WillOnce(InvokeWithoutArgs(
178 this, &AudioPowerMonitorTest::SignalNotificationReceived))
179 .RetiresOnSaturation();
180 bus = CreateZeroedBuffer(scenario.num_channels);
181 power_monitor()->Scan(*bus, bus->frames());
182 WaitForNotificationReceived();
183
184 StopPowerMonitor();
185 }
186
187 static const float kMonoSilence[] = {
188 0.0f
189 };
190
191 static const float kMonoMaxAmplitude[] = {
192 1.0f
193 };
194
195 static const float kMonoMaxAmplitude2[] = {
196 -1.0f, 1.0f,
197 };
198
199 static const float kMonoHalfMaxAmplitude[] = {
200 0.5f, -0.5f, 0.5f, -0.5f
201 };
202
203 static const float kMonoNeedsClipping[] = {
204 5.0f, -0.5, 0.5f, -0.5f
205 };
206
207 static const float kMonoContainsInfinity[] = {
208 0.0f, 0.0f, 0.0f, std::numeric_limits<float>::infinity()
209 };
210
211 static const float kMonoContainsNaN[] = {
212 0.5f, -0.5f, 0.5f, std::numeric_limits<float>::quiet_NaN()
213 };
214
215 static const float kStereoSilence[] = {
216 // left channel
217 0.0f,
218 // right channel
219 0.0f
220 };
221
222 static const float kStereoMaxAmplitude[] = {
223 // left channel
224 1.0f, -1.0f,
225 // right channel
226 -1.0f, 1.0f
227 };
228
229 static const float kRightChannelMaxAmplitude[] = {
230 // left channel
231 0.0f, 0.0f, 0.0f, 0.0f,
232 // right channel
233 -1.0f, 1.0f, -1.0f, 1.0f
234 };
235
236 static const float kLeftChannelHalfMaxAmplitude[] = {
237 // left channel
238 0.5f, -0.5f, 0.5f, -0.5f,
239 // right channel
240 0.0f, 0.0f, 0.0f, 0.0f,
241 };
242
243 static const float kStereoMixed[] = {
244 // left channel
245 0.5f, -0.5f, 0.5f, -0.5f,
246 // right channel
247 -1.0f, 1.0f, -1.0f, 1.0f
248 };
249
250 static const float kStereoMixed2[] = {
251 // left channel
252 1.0f, -1.0f, 0.5f, -0.5f, 0.25f, -0.25f, 0.125f, -0.125f,
253 // right channel
254 0.125f, -0.125f, 0.25f, -0.25f, 0.5f, -0.5f, 1.0f, -1.0f
255 };
256
257 INSTANTIATE_TEST_CASE_P(
258 Scenarios, AudioPowerMonitorTest,
259 Values(
260 TestScenario(kMonoSilence, 1, 1,
261 AudioPowerMonitor::kZeroPowerDBFS),
262 TestScenario(kMonoMaxAmplitude, 1, 1,
263 AudioPowerMonitor::kMaxPowerDBFS),
264 TestScenario(kMonoMaxAmplitude2, 1, 2,
265 AudioPowerMonitor::kMaxPowerDBFS),
266 TestScenario(kMonoHalfMaxAmplitude, 1, 4,
267 -6.0206f),
268 TestScenario(kMonoNeedsClipping, 1, 4,
269 AudioPowerMonitor::kMaxPowerDBFS),
270 TestScenario(kMonoContainsInfinity, 1, 4,
271 AudioPowerMonitor::kMaxPowerDBFS),
272 TestScenario(kMonoContainsNaN, 1, 4,
273 AudioPowerMonitor::kZeroPowerDBFS),
274 TestScenario(kStereoSilence, 2, 1,
275 AudioPowerMonitor::kZeroPowerDBFS),
276 TestScenario(kStereoMaxAmplitude, 2, 2,
277 AudioPowerMonitor::kMaxPowerDBFS),
278 TestScenario(kRightChannelMaxAmplitude, 2, 4,
279 -3.0103f),
280 TestScenario(kLeftChannelHalfMaxAmplitude, 2, 4,
281 -9.0309f),
282 TestScenario(kStereoMixed, 2, 4,
283 -2.0412f),
284 TestScenario(kStereoMixed2, 2, 8,
285 -4.78821f)));
286
287 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698