blob: fe678a02a8086685f6d5eaa5601c1e87745901b0 [file] [log] [blame]
andrew@webrtc.orga7b57da2012-10-22 18:19:23 +00001/*
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 "gtest/gtest.h"
14
15#include "output_mixer.h"
16#include "output_mixer_internal.h"
17
18namespace webrtc {
19namespace voe {
20namespace {
21
22class OutputMixerTest : public ::testing::Test {
23 protected:
24 OutputMixerTest() {
25 src_frame_.sample_rate_hz_ = 16000;
26 src_frame_.samples_per_channel_ = src_frame_.sample_rate_hz_ / 100;
27 src_frame_.num_channels_ = 1;
28 dst_frame_ = src_frame_;
29 golden_frame_ = src_frame_;
30 }
31
32 void RunResampleTest(int src_channels, int src_sample_rate_hz,
33 int dst_channels, int dst_sample_rate_hz);
34
35 Resampler resampler_;
36 AudioFrame src_frame_;
37 AudioFrame dst_frame_;
38 AudioFrame golden_frame_;
39};
40
41// Sets the signal value to increase by |data| with every sample. Floats are
42// used so non-integer values result in rounding error, but not an accumulating
43// error.
44void SetMonoFrame(AudioFrame* frame, float data, int sample_rate_hz) {
45 frame->num_channels_ = 1;
46 frame->sample_rate_hz_ = sample_rate_hz;
47 frame->samples_per_channel_ = sample_rate_hz / 100;
48 for (int i = 0; i < frame->samples_per_channel_; i++) {
49 frame->data_[i] = data * i;
50 }
51}
52
53// Keep the existing sample rate.
54void SetMonoFrame(AudioFrame* frame, float data) {
55 SetMonoFrame(frame, data, frame->sample_rate_hz_);
56}
57
58// Sets the signal value to increase by |left| and |right| with every sample in
59// each channel respectively.
60void SetStereoFrame(AudioFrame* frame, float left, float right,
61 int sample_rate_hz) {
62 frame->num_channels_ = 2;
63 frame->sample_rate_hz_ = sample_rate_hz;
64 frame->samples_per_channel_ = sample_rate_hz / 100;
65 for (int i = 0; i < frame->samples_per_channel_; i++) {
66 frame->data_[i * 2] = left * i;
67 frame->data_[i * 2 + 1] = right * i;
68 }
69}
70
71// Keep the existing sample rate.
72void SetStereoFrame(AudioFrame* frame, float left, float right) {
73 SetStereoFrame(frame, left, right, frame->sample_rate_hz_);
74}
75
76void VerifyParams(const AudioFrame& ref_frame, const AudioFrame& test_frame) {
77 EXPECT_EQ(ref_frame.num_channels_, test_frame.num_channels_);
78 EXPECT_EQ(ref_frame.samples_per_channel_, test_frame.samples_per_channel_);
79 EXPECT_EQ(ref_frame.sample_rate_hz_, test_frame.sample_rate_hz_);
80}
81
82// Computes the best SNR based on the error between |ref_frame| and
83// |test_frame|. It allows for up to a 30 sample delay between the signals to
84// compensate for the resampling delay.
85float ComputeSNR(const AudioFrame& ref_frame, const AudioFrame& test_frame) {
86 VerifyParams(ref_frame, test_frame);
87 float best_snr = 0;
88 int best_delay = 0;
89 for (int delay = 0; delay < 30; delay++) {
90 float mse = 0;
91 float variance = 0;
92 for (int i = 0; i < ref_frame.samples_per_channel_ *
93 ref_frame.num_channels_ - delay; i++) {
94 int error = ref_frame.data_[i] - test_frame.data_[i + delay];
95 mse += error * error;
96 variance += ref_frame.data_[i] * ref_frame.data_[i];
97 }
98 float snr = 100; // We assign 100 dB to the zero-error case.
99 if (mse > 0)
100 snr = 10 * log10(variance / mse);
101 if (snr > best_snr) {
102 best_snr = snr;
103 best_delay = delay;
104 }
105 }
106 printf("SNR=%.1f dB at delay=%d\n", best_snr, best_delay);
107 return best_snr;
108}
109
110void VerifyFramesAreEqual(const AudioFrame& ref_frame,
111 const AudioFrame& test_frame) {
112 VerifyParams(ref_frame, test_frame);
113 for (int i = 0; i < ref_frame.samples_per_channel_ * ref_frame.num_channels_;
114 i++) {
115 EXPECT_EQ(ref_frame.data_[i], test_frame.data_[i]);
116 }
117}
118
119void OutputMixerTest::RunResampleTest(int src_channels,
120 int src_sample_rate_hz,
121 int dst_channels,
122 int dst_sample_rate_hz) {
123 Resampler resampler; // Create a new one with every test.
124 const int16_t kSrcLeft = 60; // Shouldn't overflow for any used sample rate.
125 const int16_t kSrcRight = 30;
126 const float kResamplingFactor = (1.0 * src_sample_rate_hz) /
127 dst_sample_rate_hz;
128 const float kDstLeft = kResamplingFactor * kSrcLeft;
129 const float kDstRight = kResamplingFactor * kSrcRight;
130 const float kDstMono = (kDstLeft + kDstRight) / 2;
131 if (src_channels == 1)
132 SetMonoFrame(&src_frame_, kSrcLeft, src_sample_rate_hz);
133 else
134 SetStereoFrame(&src_frame_, kSrcLeft, kSrcRight, src_sample_rate_hz);
135
136 if (dst_channels == 1) {
137 SetMonoFrame(&dst_frame_, 0, dst_sample_rate_hz);
138 if (src_channels == 1)
139 SetMonoFrame(&golden_frame_, kDstLeft, dst_sample_rate_hz);
140 else
141 SetMonoFrame(&golden_frame_, kDstMono, dst_sample_rate_hz);
142 } else {
143 SetStereoFrame(&dst_frame_, 0, 0, dst_sample_rate_hz);
144 if (src_channels == 1)
145 SetStereoFrame(&golden_frame_, kDstLeft, kDstLeft, dst_sample_rate_hz);
146 else
147 SetStereoFrame(&golden_frame_, kDstLeft, kDstRight, dst_sample_rate_hz);
148 }
149
150 printf("(%d, %d Hz) -> (%d, %d Hz) ", // SNR reported on the same line later.
151 src_channels, src_sample_rate_hz, dst_channels, dst_sample_rate_hz);
152 EXPECT_EQ(0, RemixAndResample(src_frame_, &resampler, &dst_frame_));
153 EXPECT_GT(ComputeSNR(golden_frame_, dst_frame_), 40.0f);
154}
155
156TEST_F(OutputMixerTest, RemixAndResampleFailsWithBadSampleRate) {
157 SetMonoFrame(&dst_frame_, 10, 44100);
158 EXPECT_EQ(-1, RemixAndResample(src_frame_, &resampler_, &dst_frame_));
159 VerifyFramesAreEqual(src_frame_, dst_frame_);
160}
161
162TEST_F(OutputMixerTest, RemixAndResampleCopyFrameSucceeds) {
163 // Stereo -> stereo.
164 SetStereoFrame(&src_frame_, 10, 10);
165 SetStereoFrame(&dst_frame_, 0, 0);
166 EXPECT_EQ(0, RemixAndResample(src_frame_, &resampler_, &dst_frame_));
167 VerifyFramesAreEqual(src_frame_, dst_frame_);
168
169 // Mono -> mono.
170 SetMonoFrame(&src_frame_, 20);
171 SetMonoFrame(&dst_frame_, 0);
172 EXPECT_EQ(0, RemixAndResample(src_frame_, &resampler_, &dst_frame_));
173 VerifyFramesAreEqual(src_frame_, dst_frame_);
174}
175
176TEST_F(OutputMixerTest, RemixAndResampleMixingOnlySucceeds) {
177 // Stereo -> mono.
178 SetStereoFrame(&dst_frame_, 0, 0);
179 SetMonoFrame(&src_frame_, 10);
180 SetStereoFrame(&golden_frame_, 10, 10);
181 EXPECT_EQ(0, RemixAndResample(src_frame_, &resampler_, &dst_frame_));
182 VerifyFramesAreEqual(dst_frame_, golden_frame_);
183
184 // Mono -> stereo.
185 SetMonoFrame(&dst_frame_, 0);
186 SetStereoFrame(&src_frame_, 10, 20);
187 SetMonoFrame(&golden_frame_, 15);
188 EXPECT_EQ(0, RemixAndResample(src_frame_, &resampler_, &dst_frame_));
189 VerifyFramesAreEqual(golden_frame_, dst_frame_);
190}
191
192TEST_F(OutputMixerTest, RemixAndResampleSucceeds) {
193 // We don't attempt to be exhaustive here, but just get good coverage. Some
194 // combinations of rates will not be resampled, and some give an odd
195 // resampling factor which makes it more difficult to evaluate.
196 const int kSampleRates[] = {16000, 32000, 48000};
197 const int kSampleRatesSize = sizeof(kSampleRates) / sizeof(*kSampleRates);
198 const int kChannels[] = {1, 2};
199 const int kChannelsSize = sizeof(kChannels) / sizeof(*kChannels);
200 for (int src_rate = 0; src_rate < kSampleRatesSize; src_rate++) {
201 for (int dst_rate = 0; dst_rate < kSampleRatesSize; dst_rate++) {
202 for (int src_channel = 0; src_channel < kChannelsSize; src_channel++) {
203 for (int dst_channel = 0; dst_channel < kChannelsSize; dst_channel++) {
204 RunResampleTest(kChannels[src_channel], kSampleRates[src_rate],
205 kChannels[dst_channel], kSampleRates[dst_rate]);
206 }
207 }
208 }
209 }
210}
211
212} // namespace
213} // namespace voe
214} // namespace webrtc