• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2011 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 <stddef.h>  // size_t
12 #include <stdlib.h>
13 
14 #include "gtest/gtest.h"
15 #include "typedefs.h"
16 #include "webrtc_vad.h"
17 
18 // TODO(bjornv): Move the internal unit tests to separate files.
19 extern "C" {
20 #include "vad_core.h"
21 #include "vad_gmm.h"
22 #include "vad_sp.h"
23 }
24 
25 namespace webrtc {
26 namespace {
27 const int16_t kModes[] = { 0, 1, 2, 3 };
28 const size_t kModesSize = sizeof(kModes) / sizeof(*kModes);
29 
30 // Rates we support.
31 const int16_t kRates[] = { 8000, 12000, 16000, 24000, 32000 };
32 const size_t kRatesSize = sizeof(kRates) / sizeof(*kRates);
33 // Frame lengths we support.
34 const int16_t kMaxFrameLength = 960;
35 const int16_t kFrameLengths[] = { 80, 120, 160, 240, 320, 480, 640,
36     kMaxFrameLength };
37 const size_t kFrameLengthsSize = sizeof(kFrameLengths) / sizeof(*kFrameLengths);
38 
39 // Returns true if the rate and frame length combination is valid.
ValidRatesAndFrameLengths(int16_t rate,int16_t frame_length)40 bool ValidRatesAndFrameLengths(int16_t rate, int16_t frame_length) {
41   if (rate == 8000) {
42     if (frame_length == 80 || frame_length == 160 || frame_length == 240) {
43       return true;
44     }
45     return false;
46   } else if (rate == 16000) {
47     if (frame_length == 160 || frame_length == 320 || frame_length == 480) {
48       return true;
49     }
50     return false;
51   }
52   if (rate == 32000) {
53     if (frame_length == 320 || frame_length == 640 || frame_length == 960) {
54       return true;
55     }
56     return false;
57   }
58 
59   return false;
60 }
61 
62 class VadTest : public ::testing::Test {
63  protected:
64   VadTest();
65   virtual void SetUp();
66   virtual void TearDown();
67 };
68 
VadTest()69 VadTest::VadTest() {
70 }
71 
SetUp()72 void VadTest::SetUp() {
73 }
74 
TearDown()75 void VadTest::TearDown() {
76 }
77 
TEST_F(VadTest,ApiTest)78 TEST_F(VadTest, ApiTest) {
79   // This API test runs through the APIs for all possible valid and invalid
80   // combinations.
81 
82   VadInst* handle = NULL;
83   int16_t zeros[kMaxFrameLength] = { 0 };
84 
85   // Construct a speech signal that will trigger the VAD in all modes. It is
86   // known that (i * i) will wrap around, but that doesn't matter in this case.
87   int16_t speech[kMaxFrameLength];
88   for (int16_t i = 0; i < kMaxFrameLength; i++) {
89     speech[i] = (i * i);
90   }
91 
92   // WebRtcVad_get_version() tests
93   char version[32];
94   EXPECT_EQ(-1, WebRtcVad_get_version(NULL, sizeof(version)));
95   EXPECT_EQ(-1, WebRtcVad_get_version(version, 1));
96   EXPECT_EQ(0, WebRtcVad_get_version(version, sizeof(version)));
97 
98   // Null instance tests
99   EXPECT_EQ(-1, WebRtcVad_Create(NULL));
100   EXPECT_EQ(-1, WebRtcVad_Init(NULL));
101   EXPECT_EQ(-1, WebRtcVad_Assign(NULL, NULL));
102   EXPECT_EQ(-1, WebRtcVad_Free(NULL));
103   EXPECT_EQ(-1, WebRtcVad_set_mode(NULL, kModes[0]));
104   EXPECT_EQ(-1, WebRtcVad_Process(NULL, kRates[0], speech, kFrameLengths[0]));
105 
106   // WebRtcVad_AssignSize tests
107   int handle_size_bytes = 0;
108   EXPECT_EQ(0, WebRtcVad_AssignSize(&handle_size_bytes));
109   EXPECT_EQ(576, handle_size_bytes);
110 
111   // WebRtcVad_Assign tests
112   void* tmp_handle = malloc(handle_size_bytes);
113   EXPECT_EQ(-1, WebRtcVad_Assign(&handle, NULL));
114   EXPECT_EQ(0, WebRtcVad_Assign(&handle, tmp_handle));
115   EXPECT_EQ(handle, tmp_handle);
116   free(tmp_handle);
117 
118   // WebRtcVad_Create()
119   ASSERT_EQ(0, WebRtcVad_Create(&handle));
120 
121   // Not initialized tests
122   EXPECT_EQ(-1, WebRtcVad_Process(handle, kRates[0], speech, kFrameLengths[0]));
123   EXPECT_EQ(-1, WebRtcVad_set_mode(handle, kModes[0]));
124 
125   // WebRtcVad_Init() test
126   ASSERT_EQ(0, WebRtcVad_Init(handle));
127 
128   // WebRtcVad_set_mode() invalid modes tests
129   EXPECT_EQ(-1, WebRtcVad_set_mode(handle, kModes[0] - 1));
130   EXPECT_EQ(-1, WebRtcVad_set_mode(handle, kModes[kModesSize - 1] + 1));
131 
132   // WebRtcVad_Process() tests
133   // NULL speech pointer
134   EXPECT_EQ(-1, WebRtcVad_Process(handle, kRates[0], NULL, kFrameLengths[0]));
135   // Invalid sampling rate
136   EXPECT_EQ(-1, WebRtcVad_Process(handle, 9999, speech, kFrameLengths[0]));
137   // All zeros as input should work
138   EXPECT_EQ(0, WebRtcVad_Process(handle, kRates[0], zeros, kFrameLengths[0]));
139   for (size_t k = 0; k < kModesSize; k++) {
140     // Test valid modes
141     EXPECT_EQ(0, WebRtcVad_set_mode(handle, kModes[k]));
142     // Loop through sampling rate and frame length combinations
143     for (size_t i = 0; i < kRatesSize; i++) {
144       for (size_t j = 0; j < kFrameLengthsSize; j++) {
145         if (ValidRatesAndFrameLengths(kRates[i], kFrameLengths[j])) {
146           EXPECT_EQ(1, WebRtcVad_Process(handle,
147                                          kRates[i],
148                                          speech,
149                                          kFrameLengths[j]));
150         } else {
151           EXPECT_EQ(-1, WebRtcVad_Process(handle,
152                                           kRates[i],
153                                           speech,
154                                           kFrameLengths[j]));
155         }
156       }
157     }
158   }
159 
160   EXPECT_EQ(0, WebRtcVad_Free(handle));
161 }
162 
TEST_F(VadTest,GMMTests)163 TEST_F(VadTest, GMMTests) {
164   int16_t delta = 0;
165   // Input value at mean.
166   EXPECT_EQ(1048576, WebRtcVad_GaussianProbability(0, 0, 128, &delta));
167   EXPECT_EQ(0, delta);
168   EXPECT_EQ(1048576, WebRtcVad_GaussianProbability(16, 128, 128, &delta));
169   EXPECT_EQ(0, delta);
170   EXPECT_EQ(1048576, WebRtcVad_GaussianProbability(-16, -128, 128, &delta));
171   EXPECT_EQ(0, delta);
172 
173   // Largest possible input to give non-zero probability.
174   EXPECT_EQ(1024, WebRtcVad_GaussianProbability(59, 0, 128, &delta));
175   EXPECT_EQ(7552, delta);
176   EXPECT_EQ(1024, WebRtcVad_GaussianProbability(75, 128, 128, &delta));
177   EXPECT_EQ(7552, delta);
178   EXPECT_EQ(1024, WebRtcVad_GaussianProbability(-75, -128, 128, &delta));
179   EXPECT_EQ(-7552, delta);
180 
181   // Too large input, should give zero probability.
182   EXPECT_EQ(0, WebRtcVad_GaussianProbability(105, 0, 128, &delta));
183   EXPECT_EQ(13440, delta);
184 }
185 
TEST_F(VadTest,SPTests)186 TEST_F(VadTest, SPTests) {
187   VadInstT* handle = (VadInstT*) malloc(sizeof(VadInstT));
188   int16_t zeros[kMaxFrameLength] = { 0 };
189   int32_t state[2] = { 0 };
190   int16_t data_in[kMaxFrameLength];
191   int16_t data_out[kMaxFrameLength];
192 
193   const int16_t kReferenceMin[32] = {
194       1600, 720, 509, 512, 532, 552, 570, 588,
195       606, 624, 642, 659, 675, 691, 707, 723,
196       1600, 544, 502, 522, 542, 561, 579, 597,
197       615, 633, 651, 667, 683, 699, 715, 731
198   };
199 
200   // Construct a speech signal that will trigger the VAD in all modes. It is
201   // known that (i * i) will wrap around, but that doesn't matter in this case.
202   for (int16_t i = 0; i < kMaxFrameLength; ++i) {
203     data_in[i] = (i * i);
204   }
205   // Input values all zeros, expect all zeros out.
206   WebRtcVad_Downsampling(zeros, data_out, state, (int) kMaxFrameLength);
207   EXPECT_EQ(0, state[0]);
208   EXPECT_EQ(0, state[1]);
209   for (int16_t i = 0; i < kMaxFrameLength / 2; ++i) {
210     EXPECT_EQ(0, data_out[i]);
211   }
212   // Make a simple non-zero data test.
213   WebRtcVad_Downsampling(data_in, data_out, state, (int) kMaxFrameLength);
214   EXPECT_EQ(207, state[0]);
215   EXPECT_EQ(2270, state[1]);
216 
217   ASSERT_EQ(0, WebRtcVad_InitCore(handle, 0));
218   for (int16_t i = 0; i < 16; ++i) {
219     int16_t value = 500 * (i + 1);
220     for (int j = 0; j < NUM_CHANNELS; ++j) {
221       // Use values both above and below initialized value.
222       EXPECT_EQ(kReferenceMin[i], WebRtcVad_FindMinimum(handle, value, j));
223       EXPECT_EQ(kReferenceMin[i + 16], WebRtcVad_FindMinimum(handle, 12000, j));
224     }
225     handle->frame_counter++;
226   }
227 
228   free(handle);
229 }
230 
231 // TODO(bjornv): Add a process test, run on file.
232 
233 }  // namespace
234 }  // namespace webrtc
235