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

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

Issue 14600025: Replace AudioSilenceDetector with an AudioPowerMonitor. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Use CancelableCallback instead of extra-task for close reply. Created 7 years, 5 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
« no previous file with comments | « media/audio/audio_silence_detector.cc ('k') | media/media.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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_silence_detector.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "base/threading/thread.h"
12 #include "base/time/time.h"
13 #include "media/base/audio_bus.h"
14 #include "testing/gmock/include/gmock/gmock.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 using ::testing::_;
18 using ::testing::InvokeWithoutArgs;
19 using ::testing::TestWithParam;
20 using ::testing::Values;
21
22 namespace media {
23
24 static const int kSampleRate = 48000;
25 static const int kFramesPerBuffer = 128;
26
27 namespace {
28
29 class MockObserver {
30 public:
31 MOCK_METHOD1(OnAudible, void(bool));
32 };
33
34 struct TestScenario {
35 const float* data;
36 int num_channels;
37 int num_frames;
38 float value_range;
39
40 TestScenario(const float* d, int c, int f, float v)
41 : data(d), num_channels(c), num_frames(f), value_range(v) {}
42 };
43
44 } // namespace
45
46 class AudioSilenceDetectorTest : public TestWithParam<TestScenario> {
47 public:
48 AudioSilenceDetectorTest()
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 ~AudioSilenceDetectorTest() {
56 SyncWithAudioThread();
57 }
58
59 AudioSilenceDetector* silence_detector() const {
60 return silence_detector_.get();
61 }
62
63 void StartSilenceDetector(float threshold, MockObserver* observer) {
64 audio_message_loop_->PostTask(
65 FROM_HERE,
66 base::Bind(&AudioSilenceDetectorTest::StartDetectorOnAudioThread,
67 base::Unretained(this), threshold, observer));
68 SyncWithAudioThread();
69 }
70
71 void StopSilenceDetector() {
72 audio_message_loop_->PostTask(
73 FROM_HERE,
74 base::Bind(&AudioSilenceDetectorTest::StopDetectorOnAudioThread,
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);
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 void SignalNotificationReceived() {
95 notification_received_.Signal();
96 }
97
98 void WaitForNotificationReceived() {
99 notification_received_.Wait();
100 }
101
102 // Post a task on the audio thread and block until it is executed. This
103 // provides a barrier: All previous tasks pending on the audio thread have
104 // completed before this method returns.
105 void SyncWithAudioThread() {
106 base::WaitableEvent done(false, false);
107 audio_message_loop_->PostTask(
108 FROM_HERE,
109 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
110 done.Wait();
111 }
112
113 private:
114 void StartDetectorOnAudioThread(float threshold, MockObserver* observer) {
115 const AudioSilenceDetector::AudibleCallback notify_is_audible =
116 base::Bind(&MockObserver::OnAudible, base::Unretained(observer));
117 silence_detector_.reset(new AudioSilenceDetector(
118 kSampleRate, base::TimeDelta::FromMilliseconds(1), threshold));
119 silence_detector_->Start(notify_is_audible);
120 }
121
122 void StopDetectorOnAudioThread() {
123 silence_detector_->Stop(true);
124 silence_detector_.reset();
125 }
126
127 scoped_ptr<base::Thread> audio_manager_thread_;
128 scoped_refptr<base::MessageLoopProxy> audio_message_loop_;
129
130 base::WaitableEvent notification_received_;
131
132 scoped_ptr<AudioSilenceDetector> silence_detector_;
133
134 DISALLOW_COPY_AND_ASSIGN(AudioSilenceDetectorTest);
135 };
136
137 TEST_P(AudioSilenceDetectorTest, TriggersAtVariousThresholds) {
138 static const float kThresholdsToTry[] =
139 { 0.0f, 0.125f, 0.25f, 0.5f, 0.75f, 1.0f };
140
141 const TestScenario& scenario = GetParam();
142
143 for (size_t i = 0; i < arraysize(kThresholdsToTry); ++i) {
144 MockObserver observer;
145
146 // Start the detector. This should cause a single callback to indicate
147 // we're starting out in silence.
148 EXPECT_CALL(observer, OnAudible(false))
149 .WillOnce(InvokeWithoutArgs(
150 this, &AudioSilenceDetectorTest::SignalNotificationReceived))
151 .RetiresOnSaturation();
152 StartSilenceDetector(kThresholdsToTry[i], &observer);
153 WaitForNotificationReceived();
154
155 // Send more data to the silence detector. For some test scenarios, the
156 // sound data will trigger a callback.
157 const bool expect_a_callback = (kThresholdsToTry[i] < scenario.value_range);
158 if (expect_a_callback) {
159 EXPECT_CALL(observer, OnAudible(true))
160 .WillOnce(InvokeWithoutArgs(
161 this, &AudioSilenceDetectorTest::SignalNotificationReceived))
162 .RetiresOnSaturation();
163 }
164 scoped_ptr<AudioBus> bus = CreatePopulatedBuffer(
165 scenario.data, scenario.num_channels, scenario.num_frames);
166 silence_detector()->Scan(bus.get(), bus->frames());
167 if (expect_a_callback)
168 WaitForNotificationReceived();
169
170 // Stop the detector. This should cause another callback to indicate we're
171 // ending in silence.
172 EXPECT_CALL(observer, OnAudible(false))
173 .WillOnce(InvokeWithoutArgs(
174 this, &AudioSilenceDetectorTest::SignalNotificationReceived))
175 .RetiresOnSaturation();
176 StopSilenceDetector();
177 WaitForNotificationReceived();
178
179 SyncWithAudioThread();
180 }
181 }
182
183 static const float kAllZeros[] = {
184 // left channel
185 0.0f,
186 // right channel
187 0.0f
188 };
189
190 static const float kAllOnes[] = {
191 // left channel
192 1.0f,
193 // right channel
194 1.0f
195 };
196
197 static const float kSilentLeftChannel[] = {
198 // left channel
199 0.5f, 0.5f, 0.5f, 0.5f,
200 // right channel
201 0.0f, 0.25f, 0.0f, 0.0f
202 };
203
204 static const float kSilentRightChannel[] = {
205 // left channel
206 1.0f, 1.0f, 0.75f, 0.5f, 1.0f,
207 // right channel
208 0.0f, 0.0f, 0.0f, 0.0f, 0.0f
209 };
210
211 static const float kAtDifferentVolumesAndBias[] = {
212 // left channel
213 1.0f, 0.9f, 0.8f, 0.7f, 0.6f, 0.5f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f,
214 // right channel
215 0.0f, 0.2f, 0.4f, 0.6f, 0.4f, 0.2f, 0.0f, 0.2f, 0.4f, 0.6f, 0.4f, 0.2f
216 };
217
218 INSTANTIATE_TEST_CASE_P(
219 Scenarios, AudioSilenceDetectorTest,
220 Values(
221 TestScenario(kAllZeros, 2, 1, 0.0f),
222 TestScenario(kAllOnes, 2, 1, 0.0f),
223 TestScenario(kSilentLeftChannel, 2, 4, 0.25f),
224 TestScenario(kSilentRightChannel, 2, 5, 0.5f),
225 TestScenario(kAtDifferentVolumesAndBias, 2, 12, 0.6f)));
226
227 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/audio_silence_detector.cc ('k') | media/media.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698