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

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

Powered by Google App Engine
This is Rietveld 408576698