Home | History | Annotate | Download | only in audio
      1 // Copyright 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 <limits>
      8 
      9 #include "base/time/time.h"
     10 #include "media/base/audio_bus.h"
     11 #include "testing/gtest/include/gtest/gtest.h"
     12 
     13 namespace media {
     14 
     15 static const int kSampleRate = 48000;
     16 static const int kFramesPerBuffer = 128;
     17 
     18 static const int kTimeConstantMillis = 5;
     19 
     20 namespace {
     21 
     22 // Container for each parameterized test's data (input and expected results).
     23 class TestScenario {
     24  public:
     25   TestScenario(const float* data, int num_channels, int num_frames,
     26                float expected_power, bool expected_clipped)
     27       : expected_power_(expected_power), expected_clipped_(expected_clipped) {
     28     CreatePopulatedBuffer(data, num_channels, num_frames);
     29   }
     30 
     31   // Copy constructor and assignment operator for ::testing::Values(...).
     32   TestScenario(const TestScenario& other) { *this = other; }
     33   TestScenario& operator=(const TestScenario& other) {
     34     this->expected_power_ = other.expected_power_;
     35     this->expected_clipped_ = other.expected_clipped_;
     36     this->bus_ = AudioBus::Create(other.bus_->channels(), other.bus_->frames());
     37     other.bus_->CopyTo(this->bus_.get());
     38     return *this;
     39   }
     40 
     41   // Returns this TestScenario, but with a bad sample value placed in the middle
     42   // of channel 0.
     43   TestScenario WithABadSample(float bad_value) const {
     44     TestScenario result(*this);
     45     result.bus_->channel(0)[result.bus_->frames() / 2] = bad_value;
     46     return result;
     47   }
     48 
     49   const AudioBus& data() const {
     50     return *bus_;
     51   }
     52 
     53   float expected_power() const {
     54     return expected_power_;
     55   }
     56 
     57   bool expected_clipped() const {
     58     return expected_clipped_;
     59   }
     60 
     61  private:
     62   // Creates an AudioBus, sized and populated with kFramesPerBuffer frames of
     63   // data.  The given test |data| is repeated to fill the buffer.
     64   void CreatePopulatedBuffer(
     65       const float* data, int num_channels, int num_frames) {
     66     bus_ = AudioBus::Create(num_channels, kFramesPerBuffer);
     67     for (int ch = 0; ch < num_channels; ++ch) {
     68       for (int frames = 0; frames < kFramesPerBuffer; frames += num_frames) {
     69         const int num_to_copy = std::min(num_frames, kFramesPerBuffer - frames);
     70         memcpy(bus_->channel(ch) + frames, data + num_frames * ch,
     71                sizeof(float) * num_to_copy);
     72       }
     73     }
     74   }
     75 
     76   float expected_power_;
     77   bool expected_clipped_;
     78   scoped_ptr<AudioBus> bus_;
     79 };
     80 
     81 // Value printer for TestScenario.  Required to prevent Valgrind "access to
     82 // uninitialized memory" errors (http://crbug.com/263315).
     83 ::std::ostream& operator<<(::std::ostream& os, const TestScenario& ts) {
     84   return os << "{" << ts.data().channels() << "-channel signal} --> {"
     85             << ts.expected_power() << " dBFS, "
     86             << (ts.expected_clipped() ? "clipped" : "not clipped")
     87             << "}";
     88 }
     89 
     90 // An observer that receives power measurements.  Each power measurement should
     91 // should make progress towards the goal value.
     92 class MeasurementObserver {
     93  public:
     94   MeasurementObserver(float goal_power_measurement, bool goal_clipped)
     95       : goal_power_measurement_(goal_power_measurement),
     96         goal_clipped_(goal_clipped), measurement_count_(0),
     97         last_power_measurement_(AudioPowerMonitor::zero_power()),
     98         last_clipped_(false) {}
     99 
    100   int measurement_count() const {
    101     return measurement_count_;
    102   }
    103 
    104   float last_power_measurement() const {
    105     return last_power_measurement_;
    106   }
    107 
    108   bool last_clipped() const {
    109     return last_clipped_;
    110   }
    111 
    112   void OnPowerMeasured(float cur_power_measurement, bool clipped) {
    113     if (measurement_count_ == 0) {
    114       measurements_should_increase_ =
    115           (cur_power_measurement < goal_power_measurement_);
    116     } else {
    117       SCOPED_TRACE(::testing::Message()
    118                    << "Power: goal=" << goal_power_measurement_
    119                    << "; last=" << last_power_measurement_
    120                    << "; cur=" << cur_power_measurement);
    121 
    122       if (last_power_measurement_ != goal_power_measurement_) {
    123         if (measurements_should_increase_) {
    124           EXPECT_LE(last_power_measurement_, cur_power_measurement)
    125               << "Measurements should be monotonically increasing.";
    126         } else {
    127           EXPECT_GE(last_power_measurement_, cur_power_measurement)
    128               << "Measurements should be monotonically decreasing.";
    129         }
    130       } else {
    131         EXPECT_EQ(last_power_measurement_, cur_power_measurement)
    132             << "Measurements are numerically unstable at goal value.";
    133       }
    134     }
    135 
    136     last_power_measurement_ = cur_power_measurement;
    137     last_clipped_ = clipped;
    138     ++measurement_count_;
    139   }
    140 
    141  private:
    142   const float goal_power_measurement_;
    143   const bool goal_clipped_;
    144   int measurement_count_;
    145   bool measurements_should_increase_;
    146   float last_power_measurement_;
    147   bool last_clipped_;
    148 
    149   DISALLOW_COPY_AND_ASSIGN(MeasurementObserver);
    150 };
    151 
    152 }  // namespace
    153 
    154 class AudioPowerMonitorTest : public ::testing::TestWithParam<TestScenario> {
    155  public:
    156   AudioPowerMonitorTest()
    157       : power_monitor_(kSampleRate,
    158                        base::TimeDelta::FromMilliseconds(kTimeConstantMillis)) {
    159   }
    160 
    161   void FeedAndCheckExpectedPowerIsMeasured(
    162       const AudioBus& bus, float power, bool clipped) {
    163     // Feed the AudioPowerMonitor, read measurements from it, and record them in
    164     // MeasurementObserver.
    165     static const int kNumFeedIters = 100;
    166     MeasurementObserver observer(power, clipped);
    167     for (int i = 0; i < kNumFeedIters; ++i) {
    168       power_monitor_.Scan(bus, bus.frames());
    169       const std::pair<float, bool>& reading =
    170           power_monitor_.ReadCurrentPowerAndClip();
    171       observer.OnPowerMeasured(reading.first, reading.second);
    172     }
    173 
    174     // Check that the results recorded by the observer are the same whole-number
    175     // dBFS.
    176     EXPECT_EQ(static_cast<int>(power),
    177               static_cast<int>(observer.last_power_measurement()));
    178     EXPECT_EQ(clipped, observer.last_clipped());
    179   }
    180 
    181  private:
    182   AudioPowerMonitor power_monitor_;
    183 
    184   DISALLOW_COPY_AND_ASSIGN(AudioPowerMonitorTest);
    185 };
    186 
    187 TEST_P(AudioPowerMonitorTest, MeasuresPowerOfSignal) {
    188   const TestScenario& scenario = GetParam();
    189 
    190   scoped_ptr<AudioBus> zeroed_bus =
    191       AudioBus::Create(scenario.data().channels(), scenario.data().frames());
    192   zeroed_bus->Zero();
    193 
    194   // Send a "zero power" audio signal, then this scenario's audio signal, then
    195   // the "zero power" audio signal again; testing that the power monitor
    196   // measurements match expected values.
    197   FeedAndCheckExpectedPowerIsMeasured(
    198       *zeroed_bus, AudioPowerMonitor::zero_power(), false);
    199   FeedAndCheckExpectedPowerIsMeasured(
    200       scenario.data(), scenario.expected_power(), scenario.expected_clipped());
    201   FeedAndCheckExpectedPowerIsMeasured(
    202       *zeroed_bus, AudioPowerMonitor::zero_power(), false);
    203 }
    204 
    205 static const float kMonoSilentNoise[] = {
    206   0.01f, -0.01f
    207 };
    208 
    209 static const float kMonoMaxAmplitude[] = {
    210   1.0f
    211 };
    212 
    213 static const float kMonoMaxAmplitude2[] = {
    214   -1.0f, 1.0f
    215 };
    216 
    217 static const float kMonoHalfMaxAmplitude[] = {
    218   0.5f, -0.5f, 0.5f, -0.5f
    219 };
    220 
    221 static const float kMonoAmplitudeClipped[] = {
    222   2.0f, -2.0f
    223 };
    224 
    225 static const float kMonoMaxAmplitudeWithClip[] = {
    226   2.0f, 0.0, 0.0f, 0.0f
    227 };
    228 
    229 static const float kMonoMaxAmplitudeWithClip2[] = {
    230   4.0f, 0.0, 0.0f, 0.0f
    231 };
    232 
    233 static const float kStereoSilentNoise[] = {
    234   // left channel
    235   0.005f, -0.005f,
    236   // right channel
    237   0.005f, -0.005f
    238 };
    239 
    240 static const float kStereoMaxAmplitude[] = {
    241   // left channel
    242   1.0f, -1.0f,
    243   // right channel
    244   -1.0f, 1.0f
    245 };
    246 
    247 static const float kRightChannelMaxAmplitude[] = {
    248   // left channel
    249   0.0f, 0.0f, 0.0f, 0.0f,
    250   // right channel
    251   -1.0f, 1.0f, -1.0f, 1.0f
    252 };
    253 
    254 static const float kLeftChannelHalfMaxAmplitude[] = {
    255   // left channel
    256   0.5f, -0.5f, 0.5f, -0.5f,
    257   // right channel
    258   0.0f, 0.0f, 0.0f, 0.0f,
    259 };
    260 
    261 static const float kStereoMixed[] = {
    262   // left channel
    263   0.5f, -0.5f, 0.5f, -0.5f,
    264   // right channel
    265   -1.0f, 1.0f, -1.0f, 1.0f
    266 };
    267 
    268 static const float kStereoMixed2[] = {
    269   // left channel
    270   1.0f, -1.0f, 0.75f, -0.75f, 0.5f, -0.5f, 0.25f, -0.25f,
    271   // right channel
    272   0.25f, -0.25f, 0.5f, -0.5f, 0.75f, -0.75f, 1.0f, -1.0f
    273 };
    274 
    275 INSTANTIATE_TEST_CASE_P(
    276     Scenarios, AudioPowerMonitorTest,
    277     ::testing::Values(
    278          TestScenario(kMonoSilentNoise, 1, 2, -40, false),
    279          TestScenario(kMonoMaxAmplitude, 1, 1,
    280                       AudioPowerMonitor::max_power(), false),
    281          TestScenario(kMonoMaxAmplitude2, 1, 2,
    282                       AudioPowerMonitor::max_power(), false),
    283          TestScenario(kMonoHalfMaxAmplitude, 1, 4, -6, false),
    284          TestScenario(kMonoAmplitudeClipped, 1, 2,
    285                       AudioPowerMonitor::max_power(), true),
    286          TestScenario(kMonoMaxAmplitudeWithClip, 1, 4,
    287                       AudioPowerMonitor::max_power(), true),
    288          TestScenario(kMonoMaxAmplitudeWithClip2, 1, 4,
    289                       AudioPowerMonitor::max_power(), true),
    290          TestScenario(kMonoSilentNoise, 1, 2,
    291                       AudioPowerMonitor::zero_power(), false).
    292              WithABadSample(std::numeric_limits<float>::infinity()),
    293          TestScenario(kMonoHalfMaxAmplitude, 1, 4,
    294                       AudioPowerMonitor::zero_power(), false).
    295              WithABadSample(std::numeric_limits<float>::quiet_NaN()),
    296          TestScenario(kStereoSilentNoise, 2, 2, -46, false),
    297          TestScenario(kStereoMaxAmplitude, 2, 2,
    298                       AudioPowerMonitor::max_power(), false),
    299          TestScenario(kRightChannelMaxAmplitude, 2, 4, -3, false),
    300          TestScenario(kLeftChannelHalfMaxAmplitude, 2, 4, -9, false),
    301          TestScenario(kStereoMixed, 2, 4, -2, false),
    302          TestScenario(kStereoMixed2, 2, 8, -3, false)));
    303 
    304 }  // namespace media
    305