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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: media/audio/audio_power_monitor_unittest.cc
diff --git a/media/audio/audio_power_monitor_unittest.cc b/media/audio/audio_power_monitor_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..6aaa1db92799479c2753c7efb575e611fd971c44
--- /dev/null
+++ b/media/audio/audio_power_monitor_unittest.cc
@@ -0,0 +1,287 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/audio/audio_power_monitor.h"
+
+#include <cmath>
+#include <limits>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/message_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "base/time.h"
+#include "media/base/audio_bus.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::FloatEq;
+using ::testing::InvokeWithoutArgs;
+using ::testing::TestWithParam;
+using ::testing::Values;
+
+namespace media {
+
+static const int kSampleRate = 48000;
+static const int kFramesPerBuffer = 128;
+
+namespace {
+
+class MockObserver {
+ public:
+ MOCK_METHOD1(OnPowerMeasured, void(float));
+};
+
+struct TestScenario {
+ const float* data;
+ int num_channels;
+ int num_frames;
+ float power_in_dbfs;
+
+ TestScenario(const float* d, int c, int f, float p)
+ : data(d), num_channels(c), num_frames(f), power_in_dbfs(p) {}
+};
+
+} // namespace
+
+class AudioPowerMonitorTest : public TestWithParam<TestScenario> {
+ public:
+ AudioPowerMonitorTest()
+ : audio_manager_thread_(new base::Thread("AudioThread")),
+ notification_received_(false, false) {
+ audio_manager_thread_->Start();
+ audio_message_loop_ = audio_manager_thread_->message_loop_proxy();
+ }
+
+ virtual ~AudioPowerMonitorTest() {
+ SyncWithAudioThread();
+ }
+
+ AudioPowerMonitor* power_monitor() const {
+ return power_monitor_.get();
+ }
+
+ void StartPowerMonitor(MockObserver* observer) {
+ audio_message_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(&AudioPowerMonitorTest::StartMonitorOnAudioThread,
+ base::Unretained(this), observer));
+ SyncWithAudioThread();
+ }
+
+ void StopPowerMonitor() {
+ audio_message_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(&AudioPowerMonitorTest::StopMonitorOnAudioThread,
+ base::Unretained(this)));
+ SyncWithAudioThread();
+ }
+
+ // Creates an AudioBus, sized and populated with kFramesPerBuffer frames of
+ // data. The given test |data| is repeated to fill the buffer.
+ scoped_ptr<AudioBus> CreatePopulatedBuffer(
+ const float* data, int num_channels, int num_frames) {
+ scoped_ptr<AudioBus> bus = AudioBus::Create(num_channels, kFramesPerBuffer);
+ for (int ch = 0; ch < num_channels; ++ch) {
+ for (int frames = 0; frames < kFramesPerBuffer; frames += num_frames) {
+ const int num_to_copy = std::min(num_frames, kFramesPerBuffer - frames);
+ memcpy(bus->channel(ch) + frames, data + num_frames * ch,
+ sizeof(float) * num_to_copy);
+ }
+ }
+ return bus.Pass();
+ }
+
+ scoped_ptr<AudioBus> CreateZeroedBuffer(int num_channels) {
+ scoped_ptr<AudioBus> bus = AudioBus::Create(num_channels, kFramesPerBuffer);
+ bus->Zero();
+ return bus.Pass();
+ }
+
+
+ void SignalNotificationReceived() {
+ notification_received_.Signal();
+ }
+
+ void WaitForNotificationReceived() {
+ notification_received_.Wait();
+ }
+
+ // Post a task on the audio thread and block until it is executed. This
+ // provides a barrier: All previous tasks pending on the audio thread have
+ // completed before this method returns.
+ void SyncWithAudioThread() {
+ base::WaitableEvent done(false, false);
+ audio_message_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
+ done.Wait();
+ }
+
+ private:
+ void StartMonitorOnAudioThread(MockObserver* observer) {
+ const AudioPowerMonitor::PowerMeasurementCallback callback =
+ base::Bind(&MockObserver::OnPowerMeasured, base::Unretained(observer));
+ power_monitor_.reset(new AudioPowerMonitor(
+ kSampleRate, base::TimeDelta::FromMilliseconds(1),
+ MessageLoop::current(), callback));
+ }
+
+ void StopMonitorOnAudioThread() {
+ power_monitor_.reset();
+ }
+
+ scoped_ptr<base::Thread> audio_manager_thread_;
+ scoped_refptr<base::MessageLoopProxy> audio_message_loop_;
+
+ base::WaitableEvent notification_received_;
+
+ scoped_ptr<AudioPowerMonitor> power_monitor_;
+
+ DISALLOW_COPY_AND_ASSIGN(AudioPowerMonitorTest);
+};
+
+TEST_P(AudioPowerMonitorTest, MeasuresPowerOfSignal) {
+ const TestScenario& scenario = GetParam();
+
+ MockObserver observer;
+ StartPowerMonitor(&observer);
+
+ // Send silence and expect a callback with a "zero power" result.
+ EXPECT_CALL(observer,
+ OnPowerMeasured(FloatEq(AudioPowerMonitor::kZeroPowerDBFS)))
+ .WillOnce(InvokeWithoutArgs(
+ this, &AudioPowerMonitorTest::SignalNotificationReceived))
+ .RetiresOnSaturation();
+ scoped_ptr<AudioBus> bus = CreateZeroedBuffer(scenario.num_channels);
+ power_monitor()->Scan(*bus, bus->frames());
+ WaitForNotificationReceived();
+
+ // Send audio signal data to the power monitor and expect a callback with the
+ // correct result.
+ EXPECT_CALL(observer, OnPowerMeasured(FloatEq(scenario.power_in_dbfs)))
+ .WillOnce(InvokeWithoutArgs(
+ this, &AudioPowerMonitorTest::SignalNotificationReceived))
+ .RetiresOnSaturation();
+ bus = CreatePopulatedBuffer(
+ scenario.data, scenario.num_channels, scenario.num_frames);
+ power_monitor()->Scan(*bus, bus->frames());
+ WaitForNotificationReceived();
+
+ // Send silence again and expect a callback with a "zero power" result again.
+ EXPECT_CALL(observer,
+ OnPowerMeasured(FloatEq(AudioPowerMonitor::kZeroPowerDBFS)))
+ .WillOnce(InvokeWithoutArgs(
+ this, &AudioPowerMonitorTest::SignalNotificationReceived))
+ .RetiresOnSaturation();
+ bus = CreateZeroedBuffer(scenario.num_channels);
+ power_monitor()->Scan(*bus, bus->frames());
+ WaitForNotificationReceived();
+
+ StopPowerMonitor();
+}
+
+static const float kMonoSilence[] = {
+ 0.0f
+};
+
+static const float kMonoMaxAmplitude[] = {
+ 1.0f
+};
+
+static const float kMonoMaxAmplitude2[] = {
+ -1.0f, 1.0f,
+};
+
+static const float kMonoHalfMaxAmplitude[] = {
+ 0.5f, -0.5f, 0.5f, -0.5f
+};
+
+static const float kMonoNeedsClipping[] = {
+ 5.0f, -0.5, 0.5f, -0.5f
+};
+
+static const float kMonoContainsInfinity[] = {
+ 0.0f, 0.0f, 0.0f, std::numeric_limits<float>::infinity()
+};
+
+static const float kMonoContainsNaN[] = {
+ 0.5f, -0.5f, 0.5f, std::numeric_limits<float>::quiet_NaN()
+};
+
+static const float kStereoSilence[] = {
+ // left channel
+ 0.0f,
+ // right channel
+ 0.0f
+};
+
+static const float kStereoMaxAmplitude[] = {
+ // left channel
+ 1.0f, -1.0f,
+ // right channel
+ -1.0f, 1.0f
+};
+
+static const float kRightChannelMaxAmplitude[] = {
+ // left channel
+ 0.0f, 0.0f, 0.0f, 0.0f,
+ // right channel
+ -1.0f, 1.0f, -1.0f, 1.0f
+};
+
+static const float kLeftChannelHalfMaxAmplitude[] = {
+ // left channel
+ 0.5f, -0.5f, 0.5f, -0.5f,
+ // right channel
+ 0.0f, 0.0f, 0.0f, 0.0f,
+};
+
+static const float kStereoMixed[] = {
+ // left channel
+ 0.5f, -0.5f, 0.5f, -0.5f,
+ // right channel
+ -1.0f, 1.0f, -1.0f, 1.0f
+};
+
+static const float kStereoMixed2[] = {
+ // left channel
+ 1.0f, -1.0f, 0.5f, -0.5f, 0.25f, -0.25f, 0.125f, -0.125f,
+ // right channel
+ 0.125f, -0.125f, 0.25f, -0.25f, 0.5f, -0.5f, 1.0f, -1.0f
+};
+
+INSTANTIATE_TEST_CASE_P(
+ Scenarios, AudioPowerMonitorTest,
+ Values(
+ TestScenario(kMonoSilence, 1, 1,
+ AudioPowerMonitor::kZeroPowerDBFS),
+ TestScenario(kMonoMaxAmplitude, 1, 1,
+ AudioPowerMonitor::kMaxPowerDBFS),
+ TestScenario(kMonoMaxAmplitude2, 1, 2,
+ AudioPowerMonitor::kMaxPowerDBFS),
+ TestScenario(kMonoHalfMaxAmplitude, 1, 4,
+ -6.0206f),
+ TestScenario(kMonoNeedsClipping, 1, 4,
+ AudioPowerMonitor::kMaxPowerDBFS),
+ TestScenario(kMonoContainsInfinity, 1, 4,
+ AudioPowerMonitor::kMaxPowerDBFS),
+ TestScenario(kMonoContainsNaN, 1, 4,
+ AudioPowerMonitor::kZeroPowerDBFS),
+ TestScenario(kStereoSilence, 2, 1,
+ AudioPowerMonitor::kZeroPowerDBFS),
+ TestScenario(kStereoMaxAmplitude, 2, 2,
+ AudioPowerMonitor::kMaxPowerDBFS),
+ TestScenario(kRightChannelMaxAmplitude, 2, 4,
+ -3.0103f),
+ TestScenario(kLeftChannelHalfMaxAmplitude, 2, 4,
+ -9.0309f),
+ TestScenario(kStereoMixed, 2, 4,
+ -2.0412f),
+ TestScenario(kStereoMixed2, 2, 8,
+ -4.78821f)));
+
+} // namespace media

Powered by Google App Engine
This is Rietveld 408576698