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