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// Unit tests for DtmfToneGenerator class.
12
13#include "webrtc/modules/audio_coding/neteq/dtmf_tone_generator.h"
14
15#include <math.h>
16
17#include "testing/gtest/include/gtest/gtest.h"
18#include "webrtc/modules/audio_coding/neteq/audio_multi_vector.h"
19
20namespace webrtc {
21
22class DtmfToneGeneratorTest : public ::testing::Test {
23 protected:
24  static const double kLowFreqHz[16];
25  static const double kHighFreqHz[16];
26  // This is the attenuation applied to all cases.
27  const double kBaseAttenuation = 16141.0 / 16384.0;
28  const double k3dbAttenuation = 23171.0 / 32768;
29  const int kNumSamples = 10;
30
31  void TestAllTones(int fs_hz, int channels) {
32    AudioMultiVector signal(channels);
33
34    for (int event = 0; event <= 15; ++event) {
35      std::ostringstream ss;
36      ss << "Checking event " << event << " at sample rate " << fs_hz;
37      SCOPED_TRACE(ss.str());
38      const int kAttenuation = 0;
39      ASSERT_EQ(0, tone_gen_.Init(fs_hz, event, kAttenuation));
40      EXPECT_TRUE(tone_gen_.initialized());
41      EXPECT_EQ(kNumSamples, tone_gen_.Generate(kNumSamples, &signal));
42
43      double f1 = kLowFreqHz[event];
44      double f2 = kHighFreqHz[event];
45      const double pi = 3.14159265358979323846;
46
47      for (int n = 0; n < kNumSamples; ++n) {
48        double x = k3dbAttenuation * sin(2.0 * pi * f1 / fs_hz * (-n - 1)) +
49                   sin(2.0 * pi * f2 / fs_hz * (-n - 1));
50        x *= kBaseAttenuation;
51        x = ldexp(x, 14);  // Scale to Q14.
52        for (int channel = 0; channel < channels; ++channel) {
53          EXPECT_NEAR(x, static_cast<double>(signal[channel][n]), 25);
54        }
55      }
56
57      tone_gen_.Reset();
58      EXPECT_FALSE(tone_gen_.initialized());
59    }
60  }
61
62  void TestAmplitudes(int fs_hz, int channels) {
63    AudioMultiVector signal(channels);
64    AudioMultiVector ref_signal(channels);
65
66    const int event_vec[] = {0, 4, 9, 13};  // Test a few events.
67    for (int e = 0; e < 4; ++e) {
68      int event = event_vec[e];
69      // Create full-scale reference.
70      ASSERT_EQ(0, tone_gen_.Init(fs_hz, event, 0));  // 0 attenuation.
71      EXPECT_EQ(kNumSamples, tone_gen_.Generate(kNumSamples, &ref_signal));
72      // Test every 5 steps (to save time).
73      for (int attenuation = 1; attenuation <= 36; attenuation += 5) {
74        std::ostringstream ss;
75        ss << "Checking event " << event << " at sample rate " << fs_hz;
76        ss << "; attenuation " << attenuation;
77        SCOPED_TRACE(ss.str());
78        ASSERT_EQ(0, tone_gen_.Init(fs_hz, event, attenuation));
79        EXPECT_EQ(kNumSamples, tone_gen_.Generate(kNumSamples, &signal));
80        for (int n = 0; n < kNumSamples; ++n) {
81          double attenuation_factor =
82              pow(10, -static_cast<double>(attenuation) / 20);
83          // Verify that the attenuation is correct.
84          for (int channel = 0; channel < channels; ++channel) {
85            EXPECT_NEAR(attenuation_factor * ref_signal[channel][n],
86                        signal[channel][n],
87                        2);
88          }
89        }
90
91        tone_gen_.Reset();
92      }
93    }
94  }
95
96  DtmfToneGenerator tone_gen_;
97};
98
99// Low and high frequencies for events 0 through 15.
100const double DtmfToneGeneratorTest::kLowFreqHz[16] = {
101    941.0, 697.0, 697.0, 697.0, 770.0, 770.0, 770.0, 852.0,
102    852.0, 852.0, 941.0, 941.0, 697.0, 770.0, 852.0, 941.0};
103const double DtmfToneGeneratorTest::kHighFreqHz[16] = {
104    1336.0, 1209.0, 1336.0, 1477.0, 1209.0, 1336.0, 1477.0, 1209.0,
105    1336.0, 1477.0, 1209.0, 1477.0, 1633.0, 1633.0, 1633.0, 1633.0};
106
107TEST_F(DtmfToneGeneratorTest, Test8000Mono) {
108  TestAllTones(8000, 1);
109  TestAmplitudes(8000, 1);
110}
111
112TEST_F(DtmfToneGeneratorTest, Test16000Mono) {
113  TestAllTones(16000, 1);
114  TestAmplitudes(16000, 1);
115}
116
117TEST_F(DtmfToneGeneratorTest, Test32000Mono) {
118  TestAllTones(32000, 1);
119  TestAmplitudes(32000, 1);
120}
121
122TEST_F(DtmfToneGeneratorTest, Test48000Mono) {
123  TestAllTones(48000, 1);
124  TestAmplitudes(48000, 1);
125}
126
127TEST_F(DtmfToneGeneratorTest, Test8000Stereo) {
128  TestAllTones(8000, 2);
129  TestAmplitudes(8000, 2);
130}
131
132TEST_F(DtmfToneGeneratorTest, Test16000Stereo) {
133  TestAllTones(16000, 2);
134  TestAmplitudes(16000, 2);
135}
136
137TEST_F(DtmfToneGeneratorTest, Test32000Stereo) {
138  TestAllTones(32000, 2);
139  TestAmplitudes(32000, 2);
140}
141
142TEST_F(DtmfToneGeneratorTest, Test48000Stereo) {
143  TestAllTones(48000, 2);
144  TestAmplitudes(48000, 2);
145}
146
147TEST(DtmfToneGenerator, TestErrors) {
148  DtmfToneGenerator tone_gen;
149  const int kNumSamples = 10;
150  AudioMultiVector signal(1);  // One channel.
151
152  // Try to generate tones without initializing.
153  EXPECT_EQ(DtmfToneGenerator::kNotInitialized,
154            tone_gen.Generate(kNumSamples, &signal));
155
156  const int fs = 16000;       // Valid sample rate.
157  const int event = 7;        // Valid event.
158  const int attenuation = 0;  // Valid attenuation.
159  // Initialize with invalid event -1.
160  EXPECT_EQ(DtmfToneGenerator::kParameterError,
161            tone_gen.Init(fs, -1, attenuation));
162  // Initialize with invalid event 16.
163  EXPECT_EQ(DtmfToneGenerator::kParameterError,
164            tone_gen.Init(fs, 16, attenuation));
165  // Initialize with invalid attenuation -1.
166  EXPECT_EQ(DtmfToneGenerator::kParameterError, tone_gen.Init(fs, event, -1));
167  // Initialize with invalid attenuation 37.
168  EXPECT_EQ(DtmfToneGenerator::kParameterError, tone_gen.Init(fs, event, 37));
169  EXPECT_FALSE(tone_gen.initialized());  // Should still be uninitialized.
170
171  // Initialize with valid parameters.
172  ASSERT_EQ(0, tone_gen.Init(fs, event, attenuation));
173  EXPECT_TRUE(tone_gen.initialized());
174  // Negative number of samples.
175  EXPECT_EQ(DtmfToneGenerator::kParameterError, tone_gen.Generate(-1, &signal));
176  // NULL pointer to destination.
177  EXPECT_EQ(DtmfToneGenerator::kParameterError,
178            tone_gen.Generate(kNumSamples, NULL));
179}
180
181}  // namespace webrtc
182