Home | History | Annotate | Download | only in voice_engine
      1 /*
      2  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include <math.h>
     12 
     13 #include "testing/gtest/include/gtest/gtest.h"
     14 #include "webrtc/common_audio/resampler/include/push_resampler.h"
     15 #include "webrtc/modules/interface/module_common_types.h"
     16 #include "webrtc/voice_engine/utility.h"
     17 #include "webrtc/voice_engine/voice_engine_defines.h"
     18 
     19 namespace webrtc {
     20 namespace voe {
     21 namespace {
     22 
     23 enum FunctionToTest {
     24   TestRemixAndResample,
     25   TestDownConvertToCodecFormat
     26 };
     27 
     28 class UtilityTest : public ::testing::Test {
     29  protected:
     30   UtilityTest() {
     31     src_frame_.sample_rate_hz_ = 16000;
     32     src_frame_.samples_per_channel_ = src_frame_.sample_rate_hz_ / 100;
     33     src_frame_.num_channels_ = 1;
     34     dst_frame_.CopyFrom(src_frame_);
     35     golden_frame_.CopyFrom(src_frame_);
     36   }
     37 
     38   void RunResampleTest(int src_channels, int src_sample_rate_hz,
     39                        int dst_channels, int dst_sample_rate_hz,
     40                        FunctionToTest function);
     41 
     42   PushResampler<int16_t> resampler_;
     43   AudioFrame src_frame_;
     44   AudioFrame dst_frame_;
     45   AudioFrame golden_frame_;
     46 };
     47 
     48 // Sets the signal value to increase by |data| with every sample. Floats are
     49 // used so non-integer values result in rounding error, but not an accumulating
     50 // error.
     51 void SetMonoFrame(AudioFrame* frame, float data, int sample_rate_hz) {
     52   memset(frame->data_, 0, sizeof(frame->data_));
     53   frame->num_channels_ = 1;
     54   frame->sample_rate_hz_ = sample_rate_hz;
     55   frame->samples_per_channel_ = sample_rate_hz / 100;
     56   for (int i = 0; i < frame->samples_per_channel_; i++) {
     57     frame->data_[i] = data * i;
     58   }
     59 }
     60 
     61 // Keep the existing sample rate.
     62 void SetMonoFrame(AudioFrame* frame, float data) {
     63   SetMonoFrame(frame, data, frame->sample_rate_hz_);
     64 }
     65 
     66 // Sets the signal value to increase by |left| and |right| with every sample in
     67 // each channel respectively.
     68 void SetStereoFrame(AudioFrame* frame, float left, float right,
     69                     int sample_rate_hz) {
     70   memset(frame->data_, 0, sizeof(frame->data_));
     71   frame->num_channels_ = 2;
     72   frame->sample_rate_hz_ = sample_rate_hz;
     73   frame->samples_per_channel_ = sample_rate_hz / 100;
     74   for (int i = 0; i < frame->samples_per_channel_; i++) {
     75     frame->data_[i * 2] = left * i;
     76     frame->data_[i * 2 + 1] = right * i;
     77   }
     78 }
     79 
     80 // Keep the existing sample rate.
     81 void SetStereoFrame(AudioFrame* frame, float left, float right) {
     82   SetStereoFrame(frame, left, right, frame->sample_rate_hz_);
     83 }
     84 
     85 void VerifyParams(const AudioFrame& ref_frame, const AudioFrame& test_frame) {
     86   EXPECT_EQ(ref_frame.num_channels_, test_frame.num_channels_);
     87   EXPECT_EQ(ref_frame.samples_per_channel_, test_frame.samples_per_channel_);
     88   EXPECT_EQ(ref_frame.sample_rate_hz_, test_frame.sample_rate_hz_);
     89 }
     90 
     91 // Computes the best SNR based on the error between |ref_frame| and
     92 // |test_frame|. It allows for up to a |max_delay| in samples between the
     93 // signals to compensate for the resampling delay.
     94 float ComputeSNR(const AudioFrame& ref_frame, const AudioFrame& test_frame,
     95                  int max_delay) {
     96   VerifyParams(ref_frame, test_frame);
     97   float best_snr = 0;
     98   int best_delay = 0;
     99   for (int delay = 0; delay <= max_delay; delay++) {
    100     float mse = 0;
    101     float variance = 0;
    102     for (int i = 0; i < ref_frame.samples_per_channel_ *
    103         ref_frame.num_channels_ - delay; i++) {
    104       int error = ref_frame.data_[i] - test_frame.data_[i + delay];
    105       mse += error * error;
    106       variance += ref_frame.data_[i] * ref_frame.data_[i];
    107     }
    108     float snr = 100;  // We assign 100 dB to the zero-error case.
    109     if (mse > 0)
    110       snr = 10 * log10(variance / mse);
    111     if (snr > best_snr) {
    112       best_snr = snr;
    113       best_delay = delay;
    114     }
    115   }
    116   printf("SNR=%.1f dB at delay=%d\n", best_snr, best_delay);
    117   return best_snr;
    118 }
    119 
    120 void VerifyFramesAreEqual(const AudioFrame& ref_frame,
    121                           const AudioFrame& test_frame) {
    122   VerifyParams(ref_frame, test_frame);
    123   for (int i = 0; i < ref_frame.samples_per_channel_ * ref_frame.num_channels_;
    124       i++) {
    125     EXPECT_EQ(ref_frame.data_[i], test_frame.data_[i]);
    126   }
    127 }
    128 
    129 void UtilityTest::RunResampleTest(int src_channels,
    130                                   int src_sample_rate_hz,
    131                                   int dst_channels,
    132                                   int dst_sample_rate_hz,
    133                                   FunctionToTest function) {
    134   PushResampler<int16_t> resampler;  // Create a new one with every test.
    135   const int16_t kSrcLeft = 30;  // Shouldn't overflow for any used sample rate.
    136   const int16_t kSrcRight = 15;
    137   const float resampling_factor = (1.0 * src_sample_rate_hz) /
    138       dst_sample_rate_hz;
    139   const float dst_left = resampling_factor * kSrcLeft;
    140   const float dst_right = resampling_factor * kSrcRight;
    141   const float dst_mono = (dst_left + dst_right) / 2;
    142   if (src_channels == 1)
    143     SetMonoFrame(&src_frame_, kSrcLeft, src_sample_rate_hz);
    144   else
    145     SetStereoFrame(&src_frame_, kSrcLeft, kSrcRight, src_sample_rate_hz);
    146 
    147   if (dst_channels == 1) {
    148     SetMonoFrame(&dst_frame_, 0, dst_sample_rate_hz);
    149     if (src_channels == 1)
    150       SetMonoFrame(&golden_frame_, dst_left, dst_sample_rate_hz);
    151     else
    152       SetMonoFrame(&golden_frame_, dst_mono, dst_sample_rate_hz);
    153   } else {
    154     SetStereoFrame(&dst_frame_, 0, 0, dst_sample_rate_hz);
    155     if (src_channels == 1)
    156       SetStereoFrame(&golden_frame_, dst_left, dst_left, dst_sample_rate_hz);
    157     else
    158       SetStereoFrame(&golden_frame_, dst_left, dst_right, dst_sample_rate_hz);
    159   }
    160 
    161   // The sinc resampler has a known delay, which we compute here. Multiplying by
    162   // two gives us a crude maximum for any resampling, as the old resampler
    163   // typically (but not always) has lower delay.
    164   static const int kInputKernelDelaySamples = 16;
    165   const int max_delay = static_cast<double>(dst_sample_rate_hz)
    166       / src_sample_rate_hz * kInputKernelDelaySamples * dst_channels * 2;
    167   printf("(%d, %d Hz) -> (%d, %d Hz) ",  // SNR reported on the same line later.
    168       src_channels, src_sample_rate_hz, dst_channels, dst_sample_rate_hz);
    169   if (function == TestRemixAndResample) {
    170     RemixAndResample(src_frame_, &resampler, &dst_frame_);
    171   } else {
    172     int16_t mono_buffer[kMaxMonoDataSizeSamples];
    173     DownConvertToCodecFormat(src_frame_.data_,
    174                              src_frame_.samples_per_channel_,
    175                              src_frame_.num_channels_,
    176                              src_frame_.sample_rate_hz_,
    177                              dst_frame_.num_channels_,
    178                              dst_frame_.sample_rate_hz_,
    179                              mono_buffer,
    180                              &resampler,
    181                              &dst_frame_);
    182   }
    183 
    184   if (src_sample_rate_hz == 96000 && dst_sample_rate_hz == 8000) {
    185     // The sinc resampler gives poor SNR at this extreme conversion, but we
    186     // expect to see this rarely in practice.
    187     EXPECT_GT(ComputeSNR(golden_frame_, dst_frame_, max_delay), 14.0f);
    188   } else {
    189     EXPECT_GT(ComputeSNR(golden_frame_, dst_frame_, max_delay), 46.0f);
    190   }
    191 }
    192 
    193 TEST_F(UtilityTest, RemixAndResampleCopyFrameSucceeds) {
    194   // Stereo -> stereo.
    195   SetStereoFrame(&src_frame_, 10, 10);
    196   SetStereoFrame(&dst_frame_, 0, 0);
    197   RemixAndResample(src_frame_, &resampler_, &dst_frame_);
    198   VerifyFramesAreEqual(src_frame_, dst_frame_);
    199 
    200   // Mono -> mono.
    201   SetMonoFrame(&src_frame_, 20);
    202   SetMonoFrame(&dst_frame_, 0);
    203   RemixAndResample(src_frame_, &resampler_, &dst_frame_);
    204   VerifyFramesAreEqual(src_frame_, dst_frame_);
    205 }
    206 
    207 TEST_F(UtilityTest, RemixAndResampleMixingOnlySucceeds) {
    208   // Stereo -> mono.
    209   SetStereoFrame(&dst_frame_, 0, 0);
    210   SetMonoFrame(&src_frame_, 10);
    211   SetStereoFrame(&golden_frame_, 10, 10);
    212   RemixAndResample(src_frame_, &resampler_, &dst_frame_);
    213   VerifyFramesAreEqual(dst_frame_, golden_frame_);
    214 
    215   // Mono -> stereo.
    216   SetMonoFrame(&dst_frame_, 0);
    217   SetStereoFrame(&src_frame_, 10, 20);
    218   SetMonoFrame(&golden_frame_, 15);
    219   RemixAndResample(src_frame_, &resampler_, &dst_frame_);
    220   VerifyFramesAreEqual(golden_frame_, dst_frame_);
    221 }
    222 
    223 TEST_F(UtilityTest, RemixAndResampleSucceeds) {
    224   const int kSampleRates[] = {8000, 16000, 32000, 44100, 48000, 96000};
    225   const int kSampleRatesSize = sizeof(kSampleRates) / sizeof(*kSampleRates);
    226   const int kChannels[] = {1, 2};
    227   const int kChannelsSize = sizeof(kChannels) / sizeof(*kChannels);
    228   for (int src_rate = 0; src_rate < kSampleRatesSize; src_rate++) {
    229     for (int dst_rate = 0; dst_rate < kSampleRatesSize; dst_rate++) {
    230       for (int src_channel = 0; src_channel < kChannelsSize; src_channel++) {
    231         for (int dst_channel = 0; dst_channel < kChannelsSize; dst_channel++) {
    232           RunResampleTest(kChannels[src_channel], kSampleRates[src_rate],
    233                           kChannels[dst_channel], kSampleRates[dst_rate],
    234                           TestRemixAndResample);
    235         }
    236       }
    237     }
    238   }
    239 }
    240 
    241 TEST_F(UtilityTest, ConvertToCodecFormatSucceeds) {
    242   const int kSampleRates[] = {8000, 16000, 32000, 44100, 48000, 96000};
    243   const int kSampleRatesSize = sizeof(kSampleRates) / sizeof(*kSampleRates);
    244   const int kChannels[] = {1, 2};
    245   const int kChannelsSize = sizeof(kChannels) / sizeof(*kChannels);
    246   for (int src_rate = 0; src_rate < kSampleRatesSize; src_rate++) {
    247     for (int dst_rate = 0; dst_rate < kSampleRatesSize; dst_rate++) {
    248       for (int src_channel = 0; src_channel < kChannelsSize; src_channel++) {
    249         for (int dst_channel = 0; dst_channel < kChannelsSize; dst_channel++) {
    250           if (dst_rate <= src_rate && dst_channel <= src_channel) {
    251             RunResampleTest(kChannels[src_channel], kSampleRates[src_rate],
    252                             kChannels[src_channel], kSampleRates[dst_rate],
    253                             TestDownConvertToCodecFormat);
    254           }
    255         }
    256       }
    257     }
    258   }
    259 }
    260 
    261 }  // namespace
    262 }  // namespace voe
    263 }  // namespace webrtc
    264