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. 19extern "C" { 20#include "vad_core.h" 21#include "vad_gmm.h" 22#include "vad_sp.h" 23} 24 25namespace webrtc { 26namespace { 27const int16_t kModes[] = { 0, 1, 2, 3 }; 28const size_t kModesSize = sizeof(kModes) / sizeof(*kModes); 29 30// Rates we support. 31const int16_t kRates[] = { 8000, 12000, 16000, 24000, 32000 }; 32const size_t kRatesSize = sizeof(kRates) / sizeof(*kRates); 33// Frame lengths we support. 34const int16_t kMaxFrameLength = 960; 35const int16_t kFrameLengths[] = { 80, 120, 160, 240, 320, 480, 640, 36 kMaxFrameLength }; 37const size_t kFrameLengthsSize = sizeof(kFrameLengths) / sizeof(*kFrameLengths); 38 39// Returns true if the rate and frame length combination is valid. 40bool 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 62class VadTest : public ::testing::Test { 63 protected: 64 VadTest(); 65 virtual void SetUp(); 66 virtual void TearDown(); 67}; 68 69VadTest::VadTest() { 70} 71 72void VadTest::SetUp() { 73} 74 75void VadTest::TearDown() { 76} 77 78TEST_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 163TEST_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 186TEST_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